@superdoc-dev/cli 0.1.0-next.4 → 0.1.0-next.5

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 (2) hide show
  1. package/dist/index.js +840 -153
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -35729,9 +35729,9 @@ var import_fast_glob = __toESM(require_out4(), 1);
35729
35729
  // src/lib/editor.ts
35730
35730
  import { readFile, writeFile } from "node:fs/promises";
35731
35731
 
35732
- // ../../packages/superdoc/dist/chunks/index-Cd5b-X9_.es.js
35733
- var exports_index_Cd5b_X9__es = {};
35734
- __export(exports_index_Cd5b_X9__es, {
35732
+ // ../../packages/superdoc/dist/chunks/index-CWIntMYO.es.js
35733
+ var exports_index_CWIntMYO_es = {};
35734
+ __export(exports_index_CWIntMYO_es, {
35735
35735
  z: () => useCompitable,
35736
35736
  y: () => useThemeClass,
35737
35737
  x: () => createKey2,
@@ -35832,7 +35832,7 @@ __export(exports_index_Cd5b_X9__es, {
35832
35832
  $: () => throwError
35833
35833
  });
35834
35834
 
35835
- // ../../packages/superdoc/dist/chunks/SuperConverter-DP4VhX0J.es.js
35835
+ // ../../packages/superdoc/dist/chunks/SuperConverter-CZ8CpdTM.es.js
35836
35836
  init_jszip_BjHgpFjf_es();
35837
35837
 
35838
35838
  // ../../packages/superdoc/dist/chunks/helpers-BsvIMOxu.es.js
@@ -45815,7 +45815,7 @@ function v4(options, buf, offset) {
45815
45815
  return unsafeStringify(rnds);
45816
45816
  }
45817
45817
 
45818
- // ../../packages/superdoc/dist/chunks/SuperConverter-DP4VhX0J.es.js
45818
+ // ../../packages/superdoc/dist/chunks/SuperConverter-CZ8CpdTM.es.js
45819
45819
  function getDefaultExportFromCjs3(x2) {
45820
45820
  return x2 && x2.__esModule && Object.prototype.hasOwnProperty.call(x2, "default") ? x2["default"] : x2;
45821
45821
  }
@@ -78229,7 +78229,7 @@ class SuperConverter {
78229
78229
  static getStoredSuperdocVersion(docx) {
78230
78230
  return SuperConverter.getStoredCustomProperty(docx, "SuperdocVersion");
78231
78231
  }
78232
- static setStoredSuperdocVersion(docx = this.convertedXml, version3 = "1.11.0-next.9") {
78232
+ static setStoredSuperdocVersion(docx = this.convertedXml, version3 = "1.11.0-next.10") {
78233
78233
  return SuperConverter.setStoredCustomProperty(docx, "SuperdocVersion", version3, false);
78234
78234
  }
78235
78235
  static extractDocumentGuid(docx) {
@@ -78843,7 +78843,7 @@ function generateCustomXml() {
78843
78843
  return DEFAULT_CUSTOM_XML;
78844
78844
  }
78845
78845
 
78846
- // ../../packages/superdoc/dist/chunks/index-Cd5b-X9_.es.js
78846
+ // ../../packages/superdoc/dist/chunks/index-CWIntMYO.es.js
78847
78847
  init_jszip_BjHgpFjf_es();
78848
78848
  init_vue_DI6_Tcq0_es();
78849
78849
 
@@ -84960,7 +84960,7 @@ class DocxZipper {
84960
84960
  }
84961
84961
  }
84962
84962
 
84963
- // ../../packages/superdoc/dist/chunks/index-Cd5b-X9_.es.js
84963
+ // ../../packages/superdoc/dist/chunks/index-CWIntMYO.es.js
84964
84964
  function getExtensionConfigField(extension, field, context = { name: "" }) {
84965
84965
  const fieldValue = extension.config[field];
84966
84966
  if (typeof fieldValue === "function") {
@@ -93628,7 +93628,13 @@ function splitBlockPatch(state2, dispatch, editor) {
93628
93628
  atEnd = $from.end(d2) == $from.pos + ($from.depth - d2);
93629
93629
  atStart = $from.start(d2) == $from.pos - ($from.depth - d2);
93630
93630
  deflt = defaultBlockAt$1($from.node(d2 - 1).contentMatchAt($from.indexAfter(d2 - 1)));
93631
- paragraphAttrs = { ...node2.attrs };
93631
+ paragraphAttrs = {
93632
+ ...node2.attrs,
93633
+ sdBlockId: null,
93634
+ sdBlockRev: null,
93635
+ paraId: null,
93636
+ textId: null
93637
+ };
93632
93638
  types3.unshift({ type: deflt || node2.type, attrs: paragraphAttrs });
93633
93639
  splitDepth = d2;
93634
93640
  break;
@@ -96250,6 +96256,107 @@ function isExtensionRulesEnabled(extension, enabled) {
96250
96256
  }
96251
96257
  return enabled;
96252
96258
  }
96259
+ var PERF_PLUGIN_LOG_THRESHOLD_MS = 1;
96260
+ var perfNow = () => {
96261
+ const perf2 = globalThis?.performance;
96262
+ return perf2?.now ? perf2.now() : Date.now();
96263
+ };
96264
+ var getPluginLabel = (plugin2, fallbackLabel) => {
96265
+ const key2 = plugin2?.spec?.key?.key || plugin2?.key?.key;
96266
+ if (key2)
96267
+ return key2;
96268
+ if (fallbackLabel)
96269
+ return fallbackLabel;
96270
+ return "pm-plugin";
96271
+ };
96272
+ var logPluginPerf = (kind, label, duration, editor) => {
96273
+ if (duration < PERF_PLUGIN_LOG_THRESHOLD_MS)
96274
+ return;
96275
+ const txnId = typeof editor?.getPerfTxnId === "function" ? editor.getPerfTxnId() : null;
96276
+ const txnLabel = Number.isFinite(txnId) ? `#${txnId}` : "";
96277
+ console.log(`[Perf] pm.${kind}${txnLabel} ${label}: ${duration.toFixed(2)}ms`);
96278
+ };
96279
+ var instrumentPmPlugin = (plugin2, label, editor) => {
96280
+ if (!plugin2 || !plugin2.spec)
96281
+ return plugin2;
96282
+ const pluginLabel = getPluginLabel(plugin2, label);
96283
+ const { spec } = plugin2;
96284
+ if (spec.state?.apply && !spec.state.apply.__sdPerfWrapped) {
96285
+ const originalApply = spec.state.apply;
96286
+ spec.state.apply = function applyWithPerf(tr, value, oldState, newState) {
96287
+ const start2 = perfNow();
96288
+ const result = originalApply.call(this, tr, value, oldState, newState);
96289
+ const duration = perfNow() - start2;
96290
+ logPluginPerf("apply", pluginLabel, duration, editor);
96291
+ return result;
96292
+ };
96293
+ spec.state.apply.__sdPerfWrapped = true;
96294
+ }
96295
+ if (typeof spec.appendTransaction === "function" && !spec.appendTransaction.__sdPerfWrapped) {
96296
+ const originalAppend = spec.appendTransaction;
96297
+ spec.appendTransaction = function appendWithPerf(transactions, oldState, newState) {
96298
+ const start2 = perfNow();
96299
+ const result = originalAppend.call(this, transactions, oldState, newState);
96300
+ const duration = perfNow() - start2;
96301
+ logPluginPerf("appendTransaction", pluginLabel, duration, editor);
96302
+ return result;
96303
+ };
96304
+ spec.appendTransaction.__sdPerfWrapped = true;
96305
+ }
96306
+ if (typeof spec.filterTransaction === "function" && !spec.filterTransaction.__sdPerfWrapped) {
96307
+ const originalFilter = spec.filterTransaction;
96308
+ spec.filterTransaction = function filterWithPerf(tr, state2) {
96309
+ const start2 = perfNow();
96310
+ const result = originalFilter.call(this, tr, state2);
96311
+ const duration = perfNow() - start2;
96312
+ logPluginPerf("filterTransaction", pluginLabel, duration, editor);
96313
+ return result;
96314
+ };
96315
+ spec.filterTransaction.__sdPerfWrapped = true;
96316
+ }
96317
+ if (typeof spec.props?.decorations === "function" && !spec.props.decorations.__sdPerfWrapped) {
96318
+ const originalDecorations = spec.props.decorations;
96319
+ spec.props.decorations = function decorationsWithPerf(state2) {
96320
+ const start2 = perfNow();
96321
+ const result = originalDecorations.call(this, state2);
96322
+ const duration = perfNow() - start2;
96323
+ logPluginPerf("decorations", pluginLabel, duration, editor);
96324
+ return result;
96325
+ };
96326
+ spec.props.decorations.__sdPerfWrapped = true;
96327
+ }
96328
+ if (typeof spec.view === "function" && !spec.view.__sdPerfWrapped) {
96329
+ const originalView = spec.view;
96330
+ spec.view = function viewWithPerf(view) {
96331
+ const pluginView = originalView.call(this, view);
96332
+ if (pluginView && typeof pluginView.update === "function" && !pluginView.update.__sdPerfWrapped) {
96333
+ const originalUpdate = pluginView.update;
96334
+ pluginView.update = function updateWithPerf(view2, prevState) {
96335
+ const start2 = perfNow();
96336
+ const result = originalUpdate.call(this, view2, prevState);
96337
+ const duration = perfNow() - start2;
96338
+ logPluginPerf("view.update", pluginLabel, duration, editor);
96339
+ return result;
96340
+ };
96341
+ pluginView.update.__sdPerfWrapped = true;
96342
+ }
96343
+ if (pluginView && typeof pluginView.destroy === "function" && !pluginView.destroy.__sdPerfWrapped) {
96344
+ const originalDestroy = pluginView.destroy;
96345
+ pluginView.destroy = function destroyWithPerf() {
96346
+ const start2 = perfNow();
96347
+ const result = originalDestroy.call(this);
96348
+ const duration = perfNow() - start2;
96349
+ logPluginPerf("view.destroy", pluginLabel, duration, editor);
96350
+ return result;
96351
+ };
96352
+ pluginView.destroy.__sdPerfWrapped = true;
96353
+ }
96354
+ return pluginView;
96355
+ };
96356
+ spec.view.__sdPerfWrapped = true;
96357
+ }
96358
+ return plugin2;
96359
+ };
96253
96360
 
96254
96361
  class ExtensionService {
96255
96362
  editor;
@@ -96353,7 +96460,7 @@ class ExtensionService {
96353
96460
  });
96354
96461
  bindingsObject = { ...Object.fromEntries(entries) };
96355
96462
  }
96356
- plugins.push(keymap(bindingsObject));
96463
+ plugins.push(instrumentPmPlugin(keymap(bindingsObject), `${extension.name}:keymap`, editor));
96357
96464
  const addInputRules = getExtensionConfigField(extension, "addInputRules", context);
96358
96465
  if (isExtensionRulesEnabled(extension, editor.options.enableInputRules) && addInputRules) {
96359
96466
  inputRules.push(...addInputRules());
@@ -96361,15 +96468,17 @@ class ExtensionService {
96361
96468
  const addPmPlugins = getExtensionConfigField(extension, "addPmPlugins", context);
96362
96469
  if (addPmPlugins) {
96363
96470
  const pmPlugins = addPmPlugins();
96364
- plugins.push(...pmPlugins);
96471
+ pmPlugins.forEach((plugin2, index22) => {
96472
+ plugins.push(instrumentPmPlugin(plugin2, `${extension.name}:pm${index22}`, editor));
96473
+ });
96365
96474
  }
96366
96475
  return plugins;
96367
96476
  }).flat();
96368
96477
  return [
96369
- inputRulesPlugin({
96478
+ instrumentPmPlugin(inputRulesPlugin({
96370
96479
  editor,
96371
96480
  rules: inputRules
96372
- }),
96481
+ }), "inputRules", editor),
96373
96482
  ...allPlugins
96374
96483
  ];
96375
96484
  }
@@ -97723,6 +97832,7 @@ var CommentsPlugin = Extension.create({
97723
97832
  const { doc: doc22, tr } = state2;
97724
97833
  const pluginState = CommentsPluginKey.getState(state2);
97725
97834
  const currentActiveThreadId = pluginState.activeThreadId;
97835
+ const layoutEngineActive = Boolean(editor.presentationEditor);
97726
97836
  const meta2 = tr.getMeta(CommentsPluginKey);
97727
97837
  if (meta2?.type === "setActiveComment" || meta2?.forceUpdate) {
97728
97838
  shouldUpdate = true;
@@ -97741,6 +97851,9 @@ var CommentsPlugin = Extension.create({
97741
97851
  return;
97742
97852
  prevDoc = doc22;
97743
97853
  shouldUpdate = false;
97854
+ if (layoutEngineActive) {
97855
+ return;
97856
+ }
97744
97857
  const decorations = [];
97745
97858
  const allCommentPositions = {};
97746
97859
  doc22.descendants((node2, pos) => {
@@ -100009,7 +100122,7 @@ var canUseDOM = () => {
100009
100122
  return false;
100010
100123
  }
100011
100124
  };
100012
- var summaryVersion = "1.11.0-next.9";
100125
+ var summaryVersion = "1.11.0-next.10";
100013
100126
  var nodeKeys = ["group", "content", "marks", "inline", "atom", "defining", "code", "tableRole", "summary"];
100014
100127
  var markKeys = ["group", "inclusive", "excludes", "spanning", "code"];
100015
100128
  function mapAttributes(attrs) {
@@ -100414,6 +100527,7 @@ class Editor extends EventEmitter2 {
100414
100527
  this.extensionStorage = {};
100415
100528
  this.#renderer = null;
100416
100529
  this.#isDestroyed = false;
100530
+ this.#perfTxnId = 0;
100417
100531
  this.#editorLifecycleState = "initialized";
100418
100532
  this.#sourcePath = null;
100419
100533
  this.presentationEditor = null;
@@ -100542,6 +100656,10 @@ class Editor extends EventEmitter2 {
100542
100656
  #commandService;
100543
100657
  #renderer;
100544
100658
  #isDestroyed;
100659
+ #perfTxnId;
100660
+ getPerfTxnId() {
100661
+ return this.#perfTxnId;
100662
+ }
100545
100663
  #editorLifecycleState;
100546
100664
  #sourcePath;
100547
100665
  get docChanged() {
@@ -101437,11 +101555,17 @@ class Editor extends EventEmitter2 {
101437
101555
  #dispatchTransaction(transaction) {
101438
101556
  if (this.isDestroyed)
101439
101557
  return;
101440
- const start2 = Date.now();
101558
+ const perf2 = this.view?.dom?.ownerDocument?.defaultView?.performance ?? globalThis.performance;
101559
+ const perfNow2 = () => perf2?.now ? perf2.now() : Date.now();
101560
+ const perfId = ++this.#perfTxnId;
101561
+ const perfStart = perfNow2();
101441
101562
  const prevState = this.state;
101442
101563
  let nextState;
101443
101564
  let transactionToApply = transaction;
101565
+ let trackTime = 0;
101566
+ let applyTime = 0;
101444
101567
  try {
101568
+ const trackStart = perfNow2();
101445
101569
  const trackChangesState = TrackChangesBasePluginKey.getState(prevState);
101446
101570
  const isTrackChangesActive = trackChangesState?.isTrackChangesActive ?? false;
101447
101571
  const skipTrackChanges = transactionToApply.getMeta("skipTrackChanges") === true;
@@ -101450,28 +101574,41 @@ class Editor extends EventEmitter2 {
101450
101574
  state: prevState,
101451
101575
  user: this.options.user
101452
101576
  }) : transactionToApply;
101577
+ trackTime = perfNow2() - trackStart;
101578
+ const applyStart = perfNow2();
101453
101579
  const { state: appliedState } = prevState.applyTransaction(transactionToApply);
101454
101580
  nextState = appliedState;
101581
+ applyTime = perfNow2() - applyStart;
101455
101582
  } catch (error) {
101583
+ const applyStart = perfNow2();
101456
101584
  nextState = prevState.apply(transactionToApply);
101585
+ applyTime = perfNow2() - applyStart;
101457
101586
  console.log(error);
101458
101587
  }
101459
101588
  const selectionHasChanged = !prevState.selection.eq(nextState.selection);
101460
101589
  this._state = nextState;
101590
+ let updateStateTime = 0;
101461
101591
  if (this.view) {
101592
+ const updateStateStart = perfNow2();
101462
101593
  this.view.updateState(nextState);
101594
+ updateStateTime = perfNow2() - updateStateStart;
101463
101595
  }
101464
- const end2 = Date.now();
101596
+ const end2 = perfNow2();
101597
+ const emitTransactionStart = perfNow2();
101465
101598
  this.emit("transaction", {
101466
101599
  editor: this,
101467
101600
  transaction: transactionToApply,
101468
- duration: end2 - start2
101601
+ duration: end2 - perfStart
101469
101602
  });
101603
+ const emitTransactionTime = perfNow2() - emitTransactionStart;
101604
+ let selectionEmitTime = 0;
101470
101605
  if (selectionHasChanged) {
101606
+ const selectionStart = perfNow2();
101471
101607
  this.emit("selectionUpdate", {
101472
101608
  editor: this,
101473
101609
  transaction: transactionToApply
101474
101610
  });
101611
+ selectionEmitTime = perfNow2() - selectionStart;
101475
101612
  }
101476
101613
  const focus = transactionToApply.getMeta("focus");
101477
101614
  if (focus) {
@@ -101489,20 +101626,26 @@ class Editor extends EventEmitter2 {
101489
101626
  transaction: transactionToApply
101490
101627
  });
101491
101628
  }
101492
- if (!transactionToApply.docChanged) {
101493
- return;
101494
- }
101495
- if (transaction.docChanged && this.converter) {
101496
- if (!this.converter.documentGuid) {
101497
- this.converter.promoteToGuid();
101498
- console.debug("Document modified - assigned GUID:", this.converter.documentGuid);
101629
+ let emitUpdateTime = 0;
101630
+ if (transactionToApply.docChanged) {
101631
+ if (transaction.docChanged && this.converter) {
101632
+ if (!this.converter.documentGuid) {
101633
+ this.converter.promoteToGuid();
101634
+ console.debug("Document modified - assigned GUID:", this.converter.documentGuid);
101635
+ }
101636
+ this.converter.documentModified = true;
101499
101637
  }
101500
- this.converter.documentModified = true;
101638
+ const emitUpdateStart = perfNow2();
101639
+ this.emit("update", {
101640
+ editor: this,
101641
+ transaction: transactionToApply
101642
+ });
101643
+ emitUpdateTime = perfNow2() - emitUpdateStart;
101501
101644
  }
101502
- this.emit("update", {
101503
- editor: this,
101504
- transaction: transactionToApply
101505
- });
101645
+ const totalTime = perfNow2() - perfStart;
101646
+ const inputType = transactionToApply.getMeta("inputType");
101647
+ const inputLabel = inputType ? ` input=${String(inputType)}` : "";
101648
+ console.log(`[Perf] dispatchTransaction#${perfId}: total=${totalTime.toFixed(2)}ms track=${trackTime.toFixed(2)}ms apply=${applyTime.toFixed(2)}ms updateState=${updateStateTime.toFixed(2)}ms emitTx=${emitTransactionTime.toFixed(2)}ms selection=${selectionEmitTime.toFixed(2)}ms emitUpdate=${emitUpdateTime.toFixed(2)}ms steps=${transactionToApply.steps.length} docChanged=${transactionToApply.docChanged}${inputLabel}`);
101506
101649
  }
101507
101650
  dispatch(tr) {
101508
101651
  this.#dispatchTransaction(tr);
@@ -101959,7 +102102,7 @@ class Editor extends EventEmitter2 {
101959
102102
  return migrations.length > 0;
101960
102103
  }
101961
102104
  processCollaborationMigrations() {
101962
- console.debug("[checkVersionMigrations] Current editor version", "1.11.0-next.9");
102105
+ console.debug("[checkVersionMigrations] Current editor version", "1.11.0-next.10");
101963
102106
  if (!this.options.ydoc)
101964
102107
  return;
101965
102108
  const metaMap = this.options.ydoc.getMap("meta");
@@ -104354,6 +104497,8 @@ var coercePmEnd = (run2) => {
104354
104497
  return typeof candidate === "number" ? candidate : undefined;
104355
104498
  };
104356
104499
  function computeLinePmRange$1(block, line) {
104500
+ if (!line)
104501
+ return {};
104357
104502
  if (block.kind !== "paragraph")
104358
104503
  return {};
104359
104504
  let pmStart;
@@ -104392,7 +104537,10 @@ function computeFragmentPmRange$1(block, lines, fromLine, toLine) {
104392
104537
  let pmStart;
104393
104538
  let pmEnd;
104394
104539
  for (let index22 = fromLine;index22 < toLine; index22 += 1) {
104395
- const range2 = computeLinePmRange$1(block, lines[index22]);
104540
+ const line = lines[index22];
104541
+ if (!line)
104542
+ continue;
104543
+ const range2 = computeLinePmRange$1(block, line);
104396
104544
  if (range2.pmStart != null && pmStart == null) {
104397
104545
  pmStart = range2.pmStart;
104398
104546
  }
@@ -109857,7 +110005,7 @@ function isMinimalWordLayout(value) {
109857
110005
  var LIST_MARKER_GAP$1 = 8;
109858
110006
  var DEFAULT_TAB_INTERVAL_PX$1 = 48;
109859
110007
  var DEFAULT_PAGE_HEIGHT_PX = 1056;
109860
- var DEFAULT_VIRTUALIZED_PAGE_GAP$1 = 72;
110008
+ var DEFAULT_VIRTUALIZED_PAGE_GAP = 72;
109861
110009
  var COMMENT_EXTERNAL_COLOR = "#B1124B";
109862
110010
  var COMMENT_INTERNAL_COLOR = "#078383";
109863
110011
  var COMMENT_INACTIVE_ALPHA = "40";
@@ -110004,10 +110152,11 @@ class DomPainter {
110004
110152
  this.virtualEnabled = false;
110005
110153
  this.virtualWindow = 5;
110006
110154
  this.virtualOverscan = 0;
110007
- this.virtualGap = DEFAULT_VIRTUALIZED_PAGE_GAP$1;
110155
+ this.virtualGap = DEFAULT_VIRTUALIZED_PAGE_GAP;
110008
110156
  this.virtualPaddingTop = null;
110009
110157
  this.topSpacerEl = null;
110010
110158
  this.bottomSpacerEl = null;
110159
+ this.virtualPagesEl = null;
110011
110160
  this.virtualGapSpacers = [];
110012
110161
  this.virtualPinnedPages = [];
110013
110162
  this.virtualMountedKey = "";
@@ -110039,7 +110188,7 @@ class DomPainter {
110039
110188
  if (typeof maybeGap === "number" && Number.isFinite(maybeGap)) {
110040
110189
  this.virtualGap = Math.max(0, maybeGap);
110041
110190
  } else {
110042
- this.virtualGap = DEFAULT_VIRTUALIZED_PAGE_GAP$1;
110191
+ this.virtualGap = DEFAULT_VIRTUALIZED_PAGE_GAP;
110043
110192
  }
110044
110193
  if (typeof options.virtualization.paddingTop === "number" && Number.isFinite(options.virtualization.paddingTop)) {
110045
110194
  this.virtualPaddingTop = Math.max(0, options.virtualization.paddingTop);
@@ -110171,7 +110320,7 @@ class DomPainter {
110171
110320
  }
110172
110321
  applyStyles$2(mount2, containerStyles);
110173
110322
  if (this.virtualEnabled) {
110174
- mount2.style.gap = `${this.virtualGap}px`;
110323
+ mount2.style.gap = "0px";
110175
110324
  this.renderVirtualized(layout, mount2);
110176
110325
  this.currentLayout = layout;
110177
110326
  this.changedBlocks.clear();
@@ -110192,7 +110341,7 @@ class DomPainter {
110192
110341
  if (!this.doc)
110193
110342
  return;
110194
110343
  this.currentLayout = layout;
110195
- const needsInit = !this.topSpacerEl || !this.bottomSpacerEl || this.mount !== mount2;
110344
+ const needsInit = !this.topSpacerEl || !this.bottomSpacerEl || !this.virtualPagesEl || this.mount !== mount2 || this.topSpacerEl.parentElement !== mount2;
110196
110345
  if (needsInit) {
110197
110346
  this.ensureVirtualizationSetup(mount2);
110198
110347
  }
@@ -110211,7 +110360,14 @@ class DomPainter {
110211
110360
  this.bottomSpacerEl = this.doc.createElement("div");
110212
110361
  this.configureSpacerElement(this.topSpacerEl, "top");
110213
110362
  this.configureSpacerElement(this.bottomSpacerEl, "bottom");
110363
+ this.virtualPagesEl = this.doc.createElement("div");
110364
+ this.virtualPagesEl.style.display = "flex";
110365
+ this.virtualPagesEl.style.flexDirection = "column";
110366
+ this.virtualPagesEl.style.alignItems = "center";
110367
+ this.virtualPagesEl.style.width = "100%";
110368
+ this.virtualPagesEl.style.gap = `${this.pageGap}px`;
110214
110369
  mount2.appendChild(this.topSpacerEl);
110370
+ mount2.appendChild(this.virtualPagesEl);
110215
110371
  mount2.appendChild(this.bottomSpacerEl);
110216
110372
  this.bindVirtualizationHandlers(mount2);
110217
110373
  }
@@ -110257,7 +110413,7 @@ class DomPainter {
110257
110413
  const offsets = new Array(this.virtualHeights.length + 1);
110258
110414
  offsets[0] = 0;
110259
110415
  for (let i3 = 0;i3 < this.virtualHeights.length; i3 += 1) {
110260
- offsets[i3 + 1] = offsets[i3] + this.virtualHeights[i3] + this.virtualGap;
110416
+ offsets[i3 + 1] = offsets[i3] + this.virtualHeights[i3] + this.pageGap;
110261
110417
  }
110262
110418
  this.virtualOffsets = offsets;
110263
110419
  }
@@ -110270,7 +110426,7 @@ class DomPainter {
110270
110426
  const n = this.virtualHeights.length;
110271
110427
  if (n <= 0)
110272
110428
  return 0;
110273
- return this.virtualOffsets[n] - this.virtualGap;
110429
+ return this.virtualOffsets[n] - this.pageGap;
110274
110430
  }
110275
110431
  getMountPaddingTopPx() {
110276
110432
  if (this.virtualPaddingTop != null)
@@ -110287,8 +110443,13 @@ class DomPainter {
110287
110443
  return Math.max(0, val);
110288
110444
  return 0;
110289
110445
  }
110446
+ onScroll() {
110447
+ if (this.virtualEnabled) {
110448
+ this.updateVirtualWindow();
110449
+ }
110450
+ }
110290
110451
  updateVirtualWindow() {
110291
- if (!this.mount || !this.topSpacerEl || !this.bottomSpacerEl || !this.currentLayout)
110452
+ if (!this.mount || !this.topSpacerEl || !this.bottomSpacerEl || !this.virtualPagesEl || !this.currentLayout)
110292
110453
  return;
110293
110454
  const layout = this.currentLayout;
110294
110455
  const N2 = layout.pages.length;
@@ -110358,7 +110519,7 @@ class DomPainter {
110358
110519
  newState.element.dataset.pageNumber = String(page.number);
110359
110520
  newState.element.dataset.pageIndex = String(i3);
110360
110521
  applyStyles$2(newState.element, pageStyles(pageSize.w, pageSize.h, this.getEffectivePageStyles()));
110361
- this.mount.insertBefore(newState.element, this.bottomSpacerEl);
110522
+ this.virtualPagesEl.appendChild(newState.element);
110362
110523
  this.pageIndexToState.set(i3, newState);
110363
110524
  } else {
110364
110525
  this.patchPage(existing, page, pageSize);
@@ -110367,6 +110528,9 @@ class DomPainter {
110367
110528
  if (this.mount.firstChild !== this.topSpacerEl) {
110368
110529
  this.mount.insertBefore(this.topSpacerEl, this.mount.firstChild);
110369
110530
  }
110531
+ if (this.virtualPagesEl.parentElement !== this.mount) {
110532
+ this.mount.insertBefore(this.virtualPagesEl, this.bottomSpacerEl);
110533
+ }
110370
110534
  this.mount.appendChild(this.bottomSpacerEl);
110371
110535
  let prevIndex = null;
110372
110536
  for (const idx of mounted) {
@@ -110375,13 +110539,13 @@ class DomPainter {
110375
110539
  this.configureSpacerElement(gap, "gap");
110376
110540
  gap.dataset.gapFrom = String(prevIndex);
110377
110541
  gap.dataset.gapTo = String(idx);
110378
- const gapHeight = this.topOfIndex(idx) - this.topOfIndex(prevIndex) - this.virtualHeights[prevIndex] - this.virtualGap * 2;
110542
+ const gapHeight = this.topOfIndex(idx) - this.topOfIndex(prevIndex) - this.virtualHeights[prevIndex] - this.pageGap * 2;
110379
110543
  gap.style.height = `${Math.max(0, Math.floor(gapHeight))}px`;
110380
110544
  this.virtualGapSpacers.push(gap);
110381
- this.mount.insertBefore(gap, this.bottomSpacerEl);
110545
+ this.virtualPagesEl.appendChild(gap);
110382
110546
  }
110383
110547
  const state2 = this.pageIndexToState.get(idx);
110384
- this.mount.insertBefore(state2.element, this.bottomSpacerEl);
110548
+ this.virtualPagesEl.appendChild(state2.element);
110385
110549
  prevIndex = idx;
110386
110550
  }
110387
110551
  this.changedBlocks.clear();
@@ -110409,7 +110573,7 @@ class DomPainter {
110409
110573
  const clampedFirst = Math.max(0, Math.min(first2, Math.max(0, n - 1)));
110410
110574
  const clampedLast = Math.max(0, Math.min(last2, Math.max(0, n - 1)));
110411
110575
  const top2 = this.topOfIndex(clampedFirst);
110412
- const bottom2 = this.topOfIndex(n) - this.topOfIndex(clampedLast + 1) - this.virtualGap;
110576
+ const bottom2 = this.topOfIndex(n) - this.topOfIndex(clampedLast + 1) - this.pageGap;
110413
110577
  this.topSpacerEl.style.height = `${Math.max(0, Math.floor(top2))}px`;
110414
110578
  this.bottomSpacerEl.style.height = `${Math.max(0, Math.floor(bottom2))}px`;
110415
110579
  }
@@ -110648,6 +110812,7 @@ class DomPainter {
110648
110812
  this.pageIndexToState.clear();
110649
110813
  this.topSpacerEl = null;
110650
110814
  this.bottomSpacerEl = null;
110815
+ this.virtualPagesEl = null;
110651
110816
  this.onScrollHandler = null;
110652
110817
  this.onWindowScrollHandler = null;
110653
110818
  this.onResizeHandler = null;
@@ -110801,7 +110966,7 @@ class DomPainter {
110801
110966
  section: "body"
110802
110967
  };
110803
110968
  const sdtBoundaries = computeSdtBoundaries(page.fragments, this.blockLookup);
110804
- const fragments = page.fragments.map((fragment, index22) => {
110969
+ const fragmentStates = page.fragments.map((fragment, index22) => {
110805
110970
  const sdtBoundary = sdtBoundaries.get(index22);
110806
110971
  const fragmentEl = this.renderFragment(fragment, contextBase, sdtBoundary);
110807
110972
  el.appendChild(fragmentEl);
@@ -110814,7 +110979,7 @@ class DomPainter {
110814
110979
  };
110815
110980
  });
110816
110981
  this.renderDecorationsForPage(el, page);
110817
- return { element: el, fragments };
110982
+ return { element: el, fragments: fragmentStates };
110818
110983
  }
110819
110984
  getEffectivePageStyles() {
110820
110985
  if (this.virtualEnabled && this.layoutMode === "vertical") {
@@ -113796,6 +113961,9 @@ var createDomPainter = (options) => {
113796
113961
  },
113797
113962
  getActiveComment() {
113798
113963
  return painter.getActiveComment();
113964
+ },
113965
+ onScroll() {
113966
+ painter.onScroll();
113799
113967
  }
113800
113968
  };
113801
113969
  };
@@ -114576,7 +114744,7 @@ function deduplicateOverlappingRects(rects) {
114576
114744
  }
114577
114745
  return result;
114578
114746
  }
114579
- function getPageOffsetX(options) {
114747
+ function getPageOffsets(options) {
114580
114748
  if (!options.painterHost || !options.viewportHost) {
114581
114749
  return null;
114582
114750
  }
@@ -114586,7 +114754,11 @@ function getPageOffsetX(options) {
114586
114754
  const pageRect = pageEl.getBoundingClientRect();
114587
114755
  const viewportRect = options.viewportHost.getBoundingClientRect();
114588
114756
  const offsetX = (pageRect.left - viewportRect.left) / options.zoom;
114589
- return offsetX;
114757
+ const offsetY = (pageRect.top - viewportRect.top) / options.zoom;
114758
+ return { x: offsetX, y: offsetY };
114759
+ }
114760
+ function getPageOffsetX(options) {
114761
+ return getPageOffsets(options)?.x ?? null;
114590
114762
  }
114591
114763
  function convertPageLocalToOverlayCoords(options) {
114592
114764
  if (!Number.isFinite(options.pageIndex) || options.pageIndex < 0) {
@@ -114601,14 +114773,20 @@ function convertPageLocalToOverlayCoords(options) {
114601
114773
  console.warn(`[PresentationEditor] #convertPageLocalToOverlayCoords: Invalid pageLocalY ${options.pageLocalY}. Expected a finite number.`);
114602
114774
  return null;
114603
114775
  }
114604
- const pageOffsetX = getPageOffsetX({
114776
+ const pageOffsets = getPageOffsets({
114605
114777
  painterHost: options.painterHost,
114606
114778
  viewportHost: options.viewportHost,
114607
114779
  zoom: options.zoom,
114608
114780
  pageIndex: options.pageIndex
114609
- }) ?? 0;
114781
+ });
114782
+ if (pageOffsets) {
114783
+ return {
114784
+ x: pageOffsets.x + options.pageLocalX,
114785
+ y: pageOffsets.y + options.pageLocalY
114786
+ };
114787
+ }
114610
114788
  return {
114611
- x: pageOffsetX + options.pageLocalX,
114789
+ x: options.pageLocalX,
114612
114790
  y: options.pageIndex * (options.pageHeight + options.pageGap) + options.pageLocalY
114613
114791
  };
114614
114792
  }
@@ -115744,6 +115922,125 @@ function normalizeZIndex(originalAttributes) {
115744
115922
  return;
115745
115923
  return Math.max(0, relativeHeight - OOXML_Z_INDEX_BASE);
115746
115924
  }
115925
+ var getNodeRevision = (node2) => {
115926
+ const attrs = node2?.attrs;
115927
+ if (!attrs)
115928
+ return null;
115929
+ const raw = attrs.sdBlockRev;
115930
+ if (typeof raw === "number" && Number.isFinite(raw))
115931
+ return raw;
115932
+ if (typeof raw === "string" && raw.trim() !== "") {
115933
+ const parsed = Number.parseInt(raw, 10);
115934
+ if (Number.isFinite(parsed))
115935
+ return parsed;
115936
+ }
115937
+ return null;
115938
+ };
115939
+
115940
+ class FlowBlockCache {
115941
+ #previous = /* @__PURE__ */ new Map;
115942
+ #next = /* @__PURE__ */ new Map;
115943
+ #hits = 0;
115944
+ #misses = 0;
115945
+ begin() {
115946
+ this.#next.clear();
115947
+ this.#hits = 0;
115948
+ this.#misses = 0;
115949
+ }
115950
+ get(id2, node2) {
115951
+ const nodeRev = getNodeRevision(node2);
115952
+ const cached = this.#previous.get(id2);
115953
+ if (!cached) {
115954
+ this.#misses++;
115955
+ if (nodeRev != null) {
115956
+ return { entry: null, nodeRev };
115957
+ }
115958
+ const nodeJson2 = JSON.stringify(node2);
115959
+ return { entry: null, nodeJson: nodeJson2 };
115960
+ }
115961
+ if (nodeRev != null && cached.nodeRev != null) {
115962
+ if (cached.nodeRev !== nodeRev) {
115963
+ this.#misses++;
115964
+ return { entry: null, nodeRev };
115965
+ }
115966
+ this.#hits++;
115967
+ return { entry: cached, nodeRev };
115968
+ }
115969
+ const nodeJson = JSON.stringify(node2);
115970
+ if (cached.nodeJson !== nodeJson) {
115971
+ this.#misses++;
115972
+ return { entry: null, nodeJson, nodeRev };
115973
+ }
115974
+ this.#hits++;
115975
+ return { entry: cached, nodeJson, nodeRev };
115976
+ }
115977
+ set(id2, nodeJson, nodeRev, blocks2, pmStart) {
115978
+ this.#next.set(id2, { nodeJson, nodeRev, blocks: blocks2, pmStart });
115979
+ }
115980
+ commit() {
115981
+ this.#previous = this.#next;
115982
+ this.#next = /* @__PURE__ */ new Map;
115983
+ }
115984
+ clear() {
115985
+ this.#previous.clear();
115986
+ this.#next.clear();
115987
+ }
115988
+ get stats() {
115989
+ return { hits: this.#hits, misses: this.#misses };
115990
+ }
115991
+ }
115992
+ function shiftBlockPositions(block, delta) {
115993
+ if (block.kind === "paragraph") {
115994
+ const paragraphBlock = block;
115995
+ return {
115996
+ ...paragraphBlock,
115997
+ runs: paragraphBlock.runs.map((run2) => ({
115998
+ ...run2,
115999
+ pmStart: run2.pmStart == null ? run2.pmStart : run2.pmStart + delta,
116000
+ pmEnd: run2.pmEnd == null ? run2.pmEnd : run2.pmEnd + delta
116001
+ }))
116002
+ };
116003
+ }
116004
+ if (block.kind === "image" || block.kind === "drawing") {
116005
+ const blockWithAttrs = block;
116006
+ if (blockWithAttrs.attrs) {
116007
+ const attrsPmStart = blockWithAttrs.attrs.pmStart;
116008
+ const attrsPmEnd = blockWithAttrs.attrs.pmEnd;
116009
+ const hasAttrsPositions = typeof attrsPmStart === "number" && Number.isFinite(attrsPmStart) || typeof attrsPmEnd === "number" && Number.isFinite(attrsPmEnd);
116010
+ if (hasAttrsPositions) {
116011
+ return {
116012
+ ...block,
116013
+ attrs: {
116014
+ ...blockWithAttrs.attrs,
116015
+ pmStart: typeof attrsPmStart === "number" && Number.isFinite(attrsPmStart) ? attrsPmStart + delta : attrsPmStart,
116016
+ pmEnd: typeof attrsPmEnd === "number" && Number.isFinite(attrsPmEnd) ? attrsPmEnd + delta : attrsPmEnd
116017
+ }
116018
+ };
116019
+ }
116020
+ }
116021
+ }
116022
+ const blockWithPos = block;
116023
+ if (blockWithPos.pmStart != null || blockWithPos.pmEnd != null) {
116024
+ return {
116025
+ ...block,
116026
+ pmStart: blockWithPos.pmStart == null ? blockWithPos.pmStart : blockWithPos.pmStart + delta,
116027
+ pmEnd: blockWithPos.pmEnd == null ? blockWithPos.pmEnd : blockWithPos.pmEnd + delta
116028
+ };
116029
+ }
116030
+ return { ...block };
116031
+ }
116032
+ function shiftCachedBlocks(blocks2, delta) {
116033
+ return blocks2.map((block) => shiftBlockPositions(block, delta));
116034
+ }
116035
+ function getStableParagraphId(node2) {
116036
+ const attrs = node2.attrs;
116037
+ if (!attrs)
116038
+ return null;
116039
+ const id2 = attrs.sdBlockId ?? attrs.paraId;
116040
+ if (id2 == null)
116041
+ return null;
116042
+ return String(id2);
116043
+ }
115747
116044
  var EIGHTHS_PER_POINT = 8;
115748
116045
  var MIN_BORDER_SIZE_PX = 0.5;
115749
116046
  var MAX_BORDER_SIZE_PX = 100;
@@ -119570,10 +119867,13 @@ function paragraphToFlowBlocks({
119570
119867
  themeColors,
119571
119868
  converters: converters2,
119572
119869
  converterContext,
119573
- enableComments = true
119870
+ enableComments = true,
119871
+ stableBlockId
119574
119872
  }) {
119873
+ const baseBlockId = stableBlockId ?? nextBlockId("paragraph");
119874
+ let inlineBlockCounter = 0;
119875
+ const stableNextBlockId = stableBlockId ? (prefix2) => `${stableBlockId}-${prefix2}-${inlineBlockCounter++}` : nextBlockId;
119575
119876
  const paragraphProps = typeof para.attrs?.paragraphProperties === "object" && para.attrs.paragraphProperties !== null ? para.attrs.paragraphProperties : {};
119576
- const baseBlockId = nextBlockId("paragraph");
119577
119877
  const { paragraphAttrs, resolvedParagraphProperties } = computeParagraphAttrs(para, converterContext);
119578
119878
  const blocks2 = [];
119579
119879
  const paraAttrs = para.attrs ?? {};
@@ -119584,7 +119884,7 @@ function paragraphToFlowBlocks({
119584
119884
  if (paragraphAttrs.pageBreakBefore) {
119585
119885
  blocks2.push({
119586
119886
  kind: "pageBreak",
119587
- id: nextBlockId("pageBreak"),
119887
+ id: stableBlockId ? `${stableBlockId}-pageBreak` : nextBlockId("pageBreak"),
119588
119888
  attrs: { source: "pageBreakBefore" }
119589
119889
  });
119590
119890
  }
@@ -119674,11 +119974,11 @@ function paragraphToFlowBlocks({
119674
119974
  bookmarks,
119675
119975
  tabOrdinal,
119676
119976
  paragraphAttrs,
119677
- nextBlockId
119977
+ nextBlockId: stableNextBlockId
119678
119978
  };
119679
119979
  const blockOptions = {
119680
119980
  blocks: blocks2,
119681
- nextBlockId,
119981
+ nextBlockId: stableNextBlockId,
119682
119982
  nextId,
119683
119983
  positions,
119684
119984
  trackedChangesConfig,
@@ -119727,13 +120027,14 @@ function paragraphToFlowBlocks({
119727
120027
  throw error;
119728
120028
  }
119729
120029
  }
119730
- return;
119731
120030
  }
119732
- } else if (SHAPE_CONVERTERS_REGISTRY[node2.type]) {
120031
+ return;
120032
+ }
120033
+ if (SHAPE_CONVERTERS_REGISTRY[node2.type]) {
119733
120034
  const anchorParagraphId = nextId();
119734
120035
  flushParagraph();
119735
120036
  const converter = SHAPE_CONVERTERS_REGISTRY[node2.type];
119736
- const drawingBlock = converter(node2, nextBlockId, positions);
120037
+ const drawingBlock = converter(node2, stableNextBlockId, positions);
119737
120038
  if (drawingBlock) {
119738
120039
  blocks2.push(attachAnchorParagraphId(drawingBlock, anchorParagraphId));
119739
120040
  }
@@ -119850,6 +120151,7 @@ function handleParagraphNode2(node2, context) {
119850
120151
  blocks: blocks2,
119851
120152
  recordBlockKind,
119852
120153
  nextBlockId,
120154
+ blockIdPrefix = "",
119853
120155
  positions,
119854
120156
  trackedChangesConfig,
119855
120157
  bookmarks,
@@ -119858,6 +120160,7 @@ function handleParagraphNode2(node2, context) {
119858
120160
  converters: converters2,
119859
120161
  converterContext,
119860
120162
  themeColors,
120163
+ flowBlockCache,
119861
120164
  enableComments
119862
120165
  } = context;
119863
120166
  const { ranges: sectionRanges, currentSectionIndex, currentParagraphIndex } = sectionState;
@@ -119874,6 +120177,44 @@ function handleParagraphNode2(node2, context) {
119874
120177
  }
119875
120178
  }
119876
120179
  const paragraphToFlowBlocks2 = converters2.paragraphToFlowBlocks;
120180
+ const stableId = getStableParagraphId(node2);
120181
+ const prefixedStableId = stableId ? `${blockIdPrefix}${stableId}` : null;
120182
+ const nodePos = positions.get(node2);
120183
+ const pmStart = nodePos?.start ?? 0;
120184
+ if (prefixedStableId && flowBlockCache) {
120185
+ const { entry: cached, nodeJson, nodeRev } = flowBlockCache.get(prefixedStableId, node2);
120186
+ if (cached) {
120187
+ const delta = pmStart - cached.pmStart;
120188
+ const reusedBlocks = shiftCachedBlocks(cached.blocks, delta);
120189
+ reusedBlocks.forEach((block) => {
120190
+ blocks2.push(block);
120191
+ recordBlockKind(block.kind);
120192
+ });
120193
+ flowBlockCache.set(prefixedStableId, nodeJson, nodeRev, reusedBlocks, pmStart);
120194
+ sectionState.currentParagraphIndex++;
120195
+ return;
120196
+ }
120197
+ const paragraphBlocks2 = paragraphToFlowBlocks2({
120198
+ para: node2,
120199
+ nextBlockId,
120200
+ positions,
120201
+ trackedChangesConfig,
120202
+ bookmarks,
120203
+ hyperlinkConfig,
120204
+ themeColors,
120205
+ converters: converters2,
120206
+ converterContext,
120207
+ enableComments,
120208
+ stableBlockId: prefixedStableId
120209
+ });
120210
+ paragraphBlocks2.forEach((block) => {
120211
+ blocks2.push(block);
120212
+ recordBlockKind(block.kind);
120213
+ });
120214
+ flowBlockCache.set(prefixedStableId, nodeJson, nodeRev, paragraphBlocks2, pmStart);
120215
+ sectionState.currentParagraphIndex++;
120216
+ return;
120217
+ }
119877
120218
  const paragraphBlocks = paragraphToFlowBlocks2({
119878
120219
  para: node2,
119879
120220
  nextBlockId,
@@ -119882,9 +120223,10 @@ function handleParagraphNode2(node2, context) {
119882
120223
  bookmarks,
119883
120224
  hyperlinkConfig,
119884
120225
  themeColors,
119885
- converterContext,
119886
120226
  converters: converters2,
119887
- enableComments
120227
+ converterContext,
120228
+ enableComments,
120229
+ stableBlockId: prefixedStableId ?? undefined
119888
120230
  });
119889
120231
  paragraphBlocks.forEach((block) => {
119890
120232
  blocks2.push(block);
@@ -119924,7 +120266,10 @@ function toFlowBlocks(pmDoc, options) {
119924
120266
  const instrumentation = options?.instrumentation;
119925
120267
  const idPrefix = normalizePrefix(options?.blockIdPrefix);
119926
120268
  const doc22 = pmDoc;
120269
+ const flowBlockCache = options?.flowBlockCache;
120270
+ flowBlockCache?.begin();
119927
120271
  if (!doc22.content) {
120272
+ flowBlockCache?.commit();
119928
120273
  return { blocks: [], bookmarks: /* @__PURE__ */ new Map };
119929
120274
  }
119930
120275
  const trackedChangesMode = isValidTrackedMode(options?.trackedChangesMode) ? options.trackedChangesMode : "review";
@@ -119937,6 +120282,7 @@ function toFlowBlocks(pmDoc, options) {
119937
120282
  enableRichHyperlinks: options?.enableRichHyperlinks ?? false
119938
120283
  };
119939
120284
  const enableComments = options?.enableComments ?? true;
120285
+ const themeColors = options?.themeColors;
119940
120286
  const converterContext = normalizeConverterContext(options?.converterContext, defaultFont, defaultSize);
119941
120287
  const blocks2 = [];
119942
120288
  const bookmarks = /* @__PURE__ */ new Map;
@@ -119958,6 +120304,7 @@ function toFlowBlocks(pmDoc, options) {
119958
120304
  blocks: blocks2,
119959
120305
  recordBlockKind,
119960
120306
  nextBlockId,
120307
+ blockIdPrefix: idPrefix,
119961
120308
  positions,
119962
120309
  defaultFont,
119963
120310
  defaultSize,
@@ -119972,7 +120319,8 @@ function toFlowBlocks(pmDoc, options) {
119972
120319
  currentParagraphIndex: 0
119973
120320
  },
119974
120321
  converters,
119975
- themeColors: options?.themeColors
120322
+ themeColors,
120323
+ flowBlockCache
119976
120324
  };
119977
120325
  doc22.content.forEach((node2) => {
119978
120326
  const handler2 = nodeHandlers2[node2.type];
@@ -119992,6 +120340,7 @@ function toFlowBlocks(pmDoc, options) {
119992
120340
  instrumentation?.log?.({ totalBlocks: blocks2.length, blockCounts, bookmarks: bookmarks.size });
119993
120341
  const hydratedBlocks = hydrateImageBlocks(blocks2, options?.mediaFiles);
119994
120342
  const mergedBlocks = mergeDropCapParagraphs(hydratedBlocks);
120343
+ flowBlockCache?.commit();
119995
120344
  return { blocks: mergedBlocks, bookmarks };
119996
120345
  }
119997
120346
  function mergeDropCapParagraphs(blocks2) {
@@ -123678,9 +124027,9 @@ var asBoolean = (value) => {
123678
124027
  }
123679
124028
  return false;
123680
124029
  };
123681
- var layoutDebugEnabled$1 = typeof process$1 !== "undefined" && typeof process$1.env !== "undefined" && Boolean(process$1.env.SD_DEBUG_LAYOUT);
124030
+ var layoutDebugEnabled$2 = typeof process$1 !== "undefined" && typeof process$1.env !== "undefined" && Boolean(process$1.env.SD_DEBUG_LAYOUT);
123682
124031
  var layoutLog = (...args2) => {
123683
- if (!layoutDebugEnabled$1)
124032
+ if (!layoutDebugEnabled$2)
123684
124033
  return;
123685
124034
  console.log(...args2);
123686
124035
  };
@@ -126409,6 +126758,7 @@ function hasComments(run2) {
126409
126758
  var computeDirtyRegions = (previous2, next2) => {
126410
126759
  const prevMap = new Map(previous2.map((block, index22) => [block.id, { block, index: index22 }]));
126411
126760
  const nextMap = new Map(next2.map((block, index22) => [block.id, { block, index: index22 }]));
126761
+ const stableBlockIds = /* @__PURE__ */ new Set;
126412
126762
  let firstDirtyIndex = next2.length;
126413
126763
  let lastStableIndex = -1;
126414
126764
  let prevPointer = 0;
@@ -126418,6 +126768,7 @@ var computeDirtyRegions = (previous2, next2) => {
126418
126768
  const nextBlock = next2[nextPointer];
126419
126769
  if (prevBlock.id === nextBlock.id && shallowEqual(prevBlock, nextBlock)) {
126420
126770
  lastStableIndex = nextPointer;
126771
+ stableBlockIds.add(prevBlock.id);
126421
126772
  prevPointer += 1;
126422
126773
  nextPointer += 1;
126423
126774
  continue;
@@ -126441,7 +126792,8 @@ var computeDirtyRegions = (previous2, next2) => {
126441
126792
  firstDirtyIndex: firstDirtyIndex === next2.length ? next2.length : firstDirtyIndex,
126442
126793
  lastStableIndex,
126443
126794
  insertedBlockIds,
126444
- deletedBlockIds
126795
+ deletedBlockIds,
126796
+ stableBlockIds
126445
126797
  };
126446
126798
  };
126447
126799
  var shallowEqual = (a2, b22) => {
@@ -126923,9 +127275,9 @@ function invalidateHeaderFooterCache(cache2, cacheState, headerBlocks, footerBlo
126923
127275
  var measureCache = new MeasureCache;
126924
127276
  var headerMeasureCache = new HeaderFooterLayoutCache;
126925
127277
  var headerFooterCacheState = new HeaderFooterCacheState;
126926
- var layoutDebugEnabled = typeof process$1 !== "undefined" && typeof process$1.env !== "undefined" && Boolean(process$1.env.SD_DEBUG_LAYOUT);
126927
- var perfLog = (...args2) => {
126928
- if (!layoutDebugEnabled)
127278
+ var layoutDebugEnabled$1 = typeof process$1 !== "undefined" && typeof process$1.env !== "undefined" && Boolean(process$1.env.SD_DEBUG_LAYOUT);
127279
+ var perfLog$1 = (...args2) => {
127280
+ if (!layoutDebugEnabled$1)
126929
127281
  return;
126930
127282
  console.log(...args2);
126931
127283
  };
@@ -127364,9 +127716,10 @@ var fitFootnoteContent = (id2, inputRanges, availableHeight, pageIndex, columnIn
127364
127716
  remainingRanges
127365
127717
  };
127366
127718
  };
127367
- async function incrementalLayout(previousBlocks, _previousLayout, nextBlocks, options, measureBlock2, headerFooter) {
127368
- performance.now();
127719
+ async function incrementalLayout(previousBlocks, _previousLayout, nextBlocks, options, measureBlock2, headerFooter, previousMeasures) {
127720
+ const dirtyStart = performance.now();
127369
127721
  const dirty = computeDirtyRegions(previousBlocks, nextBlocks);
127722
+ performance.now() - dirtyStart;
127370
127723
  if (dirty.deletedBlockIds.length > 0) {
127371
127724
  measureCache.invalidate(dirty.deletedBlockIds);
127372
127725
  }
@@ -127374,29 +127727,49 @@ async function incrementalLayout(previousBlocks, _previousLayout, nextBlocks, op
127374
127727
  if (measurementWidth <= 0 || measurementHeight <= 0) {
127375
127728
  throw new Error("incrementalLayout: invalid measurement constraints resolved from options");
127376
127729
  }
127730
+ const hasPreviousMeasures = Array.isArray(previousMeasures) && previousMeasures.length === previousBlocks.length;
127731
+ const previousConstraints = hasPreviousMeasures ? resolveMeasurementConstraints(options, previousBlocks) : null;
127732
+ const canReusePreviousMeasures = hasPreviousMeasures && previousConstraints?.measurementWidth === measurementWidth && previousConstraints?.measurementHeight === measurementHeight;
127733
+ const previousMeasuresById = canReusePreviousMeasures ? new Map(previousBlocks.map((block, index22) => [block.id, previousMeasures[index22]])) : null;
127377
127734
  const measureStart = performance.now();
127378
127735
  const constraints = { maxWidth: measurementWidth, maxHeight: measurementHeight };
127379
127736
  const measures = [];
127380
127737
  let cacheHits = 0;
127381
127738
  let cacheMisses = 0;
127739
+ let reusedMeasures = 0;
127740
+ let cacheLookupTime = 0;
127741
+ let actualMeasureTime = 0;
127382
127742
  for (const block of nextBlocks) {
127383
127743
  if (block.kind === "sectionBreak") {
127384
127744
  measures.push({ kind: "sectionBreak" });
127385
127745
  continue;
127386
127746
  }
127747
+ if (canReusePreviousMeasures && dirty.stableBlockIds.has(block.id)) {
127748
+ const previousMeasure = previousMeasuresById?.get(block.id);
127749
+ if (previousMeasure) {
127750
+ measures.push(previousMeasure);
127751
+ reusedMeasures++;
127752
+ continue;
127753
+ }
127754
+ }
127755
+ const lookupStart = performance.now();
127387
127756
  const cached = measureCache.get(block, measurementWidth, measurementHeight);
127757
+ cacheLookupTime += performance.now() - lookupStart;
127388
127758
  if (cached) {
127389
127759
  measures.push(cached);
127390
127760
  cacheHits++;
127391
127761
  continue;
127392
127762
  }
127763
+ const measureBlockStart = performance.now();
127393
127764
  const measurement = await measureBlock2(block, constraints);
127765
+ actualMeasureTime += performance.now() - measureBlockStart;
127394
127766
  measureCache.set(block, measurementWidth, measurementHeight, measurement);
127395
127767
  measures.push(measurement);
127396
127768
  cacheMisses++;
127397
127769
  }
127398
127770
  const measureEnd = performance.now();
127399
- perfLog(`[Perf] 4.1 Measure all blocks: ${(measureEnd - measureStart).toFixed(2)}ms (${cacheMisses} measured, ${cacheHits} cached)`);
127771
+ const totalMeasureTime = measureEnd - measureStart;
127772
+ perfLog$1(`[Perf] 4.1 Measure all blocks: ${totalMeasureTime.toFixed(2)}ms (${cacheMisses} measured, ${cacheHits} cached, ${reusedMeasures} reused)`);
127400
127773
  let headerContentHeights;
127401
127774
  let headerContentHeightsByRId;
127402
127775
  const hasHeaderBlocks = headerFooter?.headerBlocks && Object.keys(headerFooter.headerBlocks).length > 0;
@@ -127443,7 +127816,7 @@ async function incrementalLayout(previousBlocks, _previousLayout, nextBlocks, op
127443
127816
  }
127444
127817
  }
127445
127818
  const hfPreEnd = performance.now();
127446
- perfLog(`[Perf] 4.1.5 Pre-layout headers for height: ${(hfPreEnd - hfPreStart).toFixed(2)}ms`);
127819
+ perfLog$1(`[Perf] 4.1.5 Pre-layout headers for height: ${(hfPreEnd - hfPreStart).toFixed(2)}ms`);
127447
127820
  }
127448
127821
  let footerContentHeights;
127449
127822
  let footerContentHeightsByRId;
@@ -127498,7 +127871,7 @@ async function incrementalLayout(previousBlocks, _previousLayout, nextBlocks, op
127498
127871
  footerContentHeights = undefined;
127499
127872
  }
127500
127873
  const footerPreEnd = performance.now();
127501
- perfLog(`[Perf] 4.1.6 Pre-layout footers for height: ${(footerPreEnd - footerPreStart).toFixed(2)}ms`);
127874
+ perfLog$1(`[Perf] 4.1.6 Pre-layout footers for height: ${(footerPreEnd - footerPreStart).toFixed(2)}ms`);
127502
127875
  }
127503
127876
  const layoutStart = performance.now();
127504
127877
  let layout = layoutDocument(nextBlocks, measures, {
@@ -127510,7 +127883,9 @@ async function incrementalLayout(previousBlocks, _previousLayout, nextBlocks, op
127510
127883
  remeasureParagraph: (block, maxWidth, firstLineIndent) => remeasureParagraph(block, maxWidth, firstLineIndent)
127511
127884
  });
127512
127885
  const layoutEnd = performance.now();
127513
- perfLog(`[Perf] 4.2 Layout document (pagination): ${(layoutEnd - layoutStart).toFixed(2)}ms`);
127886
+ const layoutTime = layoutEnd - layoutStart;
127887
+ perfLog$1(`[Perf] 4.2 Layout document (pagination): ${layoutTime.toFixed(2)}ms`);
127888
+ layout.pages.length;
127514
127889
  const maxIterations = 3;
127515
127890
  let currentBlocks = nextBlocks;
127516
127891
  let currentMeasures = measures;
@@ -127527,10 +127902,10 @@ async function incrementalLayout(previousBlocks, _previousLayout, nextBlocks, op
127527
127902
  PageTokenLogger.logIterationStart(iteration, layout.pages.length);
127528
127903
  const tokenResult = resolvePageNumberTokens(layout, currentBlocks, currentMeasures, numberingCtx);
127529
127904
  if (tokenResult.affectedBlockIds.size === 0) {
127530
- perfLog(`[Perf] 4.3 Page token resolution converged after ${iteration} iterations`);
127905
+ perfLog$1(`[Perf] 4.3 Page token resolution converged after ${iteration} iterations`);
127531
127906
  break;
127532
127907
  }
127533
- perfLog(`[Perf] 4.3.${iteration + 1} Page tokens resolved: ${tokenResult.affectedBlockIds.size} blocks affected`);
127908
+ perfLog$1(`[Perf] 4.3.${iteration + 1} Page tokens resolved: ${tokenResult.affectedBlockIds.size} blocks affected`);
127534
127909
  const blockSamples = Array.from(tokenResult.affectedBlockIds).slice(0, 5);
127535
127910
  PageTokenLogger.logAffectedBlocks(iteration, tokenResult.affectedBlockIds, blockSamples);
127536
127911
  totalAffectedBlocks += tokenResult.affectedBlockIds.size;
@@ -127541,7 +127916,7 @@ async function incrementalLayout(previousBlocks, _previousLayout, nextBlocks, op
127541
127916
  const remeasureEnd = performance.now();
127542
127917
  const remeasureTime = remeasureEnd - remeasureStart;
127543
127918
  totalRemeasureTime += remeasureTime;
127544
- perfLog(`[Perf] 4.3.${iteration + 1}.1 Re-measure: ${remeasureTime.toFixed(2)}ms`);
127919
+ perfLog$1(`[Perf] 4.3.${iteration + 1}.1 Re-measure: ${remeasureTime.toFixed(2)}ms`);
127545
127920
  PageTokenLogger.logRemeasure(tokenResult.affectedBlockIds.size, remeasureTime);
127546
127921
  const oldPageCount = layout.pages.length;
127547
127922
  const relayoutStart = performance.now();
@@ -127556,10 +127931,10 @@ async function incrementalLayout(previousBlocks, _previousLayout, nextBlocks, op
127556
127931
  const relayoutEnd = performance.now();
127557
127932
  const relayoutTime = relayoutEnd - relayoutStart;
127558
127933
  totalRelayoutTime += relayoutTime;
127559
- perfLog(`[Perf] 4.3.${iteration + 1}.2 Re-layout: ${relayoutTime.toFixed(2)}ms`);
127934
+ perfLog$1(`[Perf] 4.3.${iteration + 1}.2 Re-layout: ${relayoutTime.toFixed(2)}ms`);
127560
127935
  const newPageCount = layout.pages.length;
127561
127936
  if (newPageCount === oldPageCount && iteration > 0) {
127562
- perfLog(`[Perf] 4.3 Page count stable at ${newPageCount} - breaking convergence loop`);
127937
+ perfLog$1(`[Perf] 4.3 Page count stable at ${newPageCount} - breaking convergence loop`);
127563
127938
  break;
127564
127939
  }
127565
127940
  iteration++;
@@ -127572,7 +127947,7 @@ async function incrementalLayout(previousBlocks, _previousLayout, nextBlocks, op
127572
127947
  const pageTokenEnd = performance.now();
127573
127948
  const totalTokenTime = pageTokenEnd - pageTokenStart;
127574
127949
  if (iteration > 0) {
127575
- perfLog(`[Perf] 4.3 Total page token resolution time: ${totalTokenTime.toFixed(2)}ms`);
127950
+ perfLog$1(`[Perf] 4.3 Total page token resolution time: ${totalTokenTime.toFixed(2)}ms`);
127576
127951
  PageTokenLogger.logConvergence(iteration, converged, totalTokenTime);
127577
127952
  globalMetrics.recordPageTokenMetrics({
127578
127953
  totalTimeMs: totalTokenTime,
@@ -127632,9 +128007,9 @@ async function incrementalLayout(previousBlocks, _previousLayout, nextBlocks, op
127632
128007
  return { blocks: blocks2, measuresById: measuresById2 };
127633
128008
  };
127634
128009
  const computeFootnoteLayoutPlan = (layoutForPages, idsByColumn2, measuresById2, baseReserves = [], pageColumns2) => {
127635
- const pageCount = layoutForPages.pages.length;
128010
+ const pageCount2 = layoutForPages.pages.length;
127636
128011
  const slicesByPage = /* @__PURE__ */ new Map;
127637
- const reserves2 = new Array(pageCount).fill(0);
128012
+ const reserves2 = new Array(pageCount2).fill(0);
127638
128013
  const hasContinuationByColumn = /* @__PURE__ */ new Map;
127639
128014
  const rangesByFootnoteId = /* @__PURE__ */ new Map;
127640
128015
  const cappedPages = /* @__PURE__ */ new Set;
@@ -127646,7 +128021,7 @@ async function incrementalLayout(previousBlocks, _previousLayout, nextBlocks, op
127646
128021
  const separatorSpacingBefore = resolveSeparatorSpacingBefore(rangesByFootnoteId, measuresById2, footnotesInput.separatorSpacingBefore, DEFAULT_FOOTNOTE_SEPARATOR_SPACING_BEFORE);
127647
128022
  const safeSeparatorSpacingBefore = Math.max(0, separatorSpacingBefore);
127648
128023
  let pendingByColumn = /* @__PURE__ */ new Map;
127649
- for (let pageIndex = 0;pageIndex < pageCount; pageIndex += 1) {
128024
+ for (let pageIndex = 0;pageIndex < pageCount2; pageIndex += 1) {
127650
128025
  const baseReserve = Number.isFinite(baseReserves?.[pageIndex]) ? Math.max(0, baseReserves[pageIndex]) : 0;
127651
128026
  const maxReserve = computeMaxFootnoteReserve(layoutForPages, pageIndex, baseReserve);
127652
128027
  const columns = pageColumns2.get(pageIndex);
@@ -128067,7 +128442,7 @@ async function incrementalLayout(previousBlocks, _previousLayout, nextBlocks, op
128067
128442
  footers = serializeHeaderFooterResults("footer", footerLayouts);
128068
128443
  }
128069
128444
  const hfEnd = performance.now();
128070
- perfLog(`[Perf] 4.4 Header/footer layout: ${(hfEnd - hfStart).toFixed(2)}ms`);
128445
+ perfLog$1(`[Perf] 4.4 Header/footer layout: ${(hfEnd - hfStart).toFixed(2)}ms`);
128071
128446
  const cacheStats = headerMeasureCache.getStats();
128072
128447
  globalMetrics.recordHeaderFooterCacheMetrics(cacheStats);
128073
128448
  HeaderFooterCacheLogger.logStats(cacheStats);
@@ -128629,13 +129004,30 @@ function clickToPosition(layout, blocks2, measures, containerPoint, domContainer
128629
129004
  if (blockIndex !== -1) {
128630
129005
  const measure = measures[blockIndex];
128631
129006
  if (measure && measure.kind === "paragraph") {
128632
- for (let li2 = fragment.fromLine;li2 < fragment.toLine; li2++) {
128633
- const line = measure.lines[li2];
128634
- const range2 = computeLinePmRange(blocks2[blockIndex], line);
128635
- if (range2.pmStart != null && range2.pmEnd != null) {
128636
- if (domPos >= range2.pmStart && domPos <= range2.pmEnd) {
128637
- lineIndex = li2;
128638
- break;
129007
+ if (fragment.lines && fragment.lines.length > 0) {
129008
+ for (let localIndex = 0;localIndex < fragment.lines.length; localIndex++) {
129009
+ const line = fragment.lines[localIndex];
129010
+ if (!line)
129011
+ continue;
129012
+ const range2 = computeLinePmRange(blocks2[blockIndex], line);
129013
+ if (range2.pmStart != null && range2.pmEnd != null) {
129014
+ if (domPos >= range2.pmStart && domPos <= range2.pmEnd) {
129015
+ lineIndex = fragment.fromLine + localIndex;
129016
+ break;
129017
+ }
129018
+ }
129019
+ }
129020
+ } else {
129021
+ for (let li2 = fragment.fromLine;li2 < fragment.toLine; li2++) {
129022
+ const line = measure.lines[li2];
129023
+ if (!line)
129024
+ continue;
129025
+ const range2 = computeLinePmRange(blocks2[blockIndex], line);
129026
+ if (range2.pmStart != null && range2.pmEnd != null) {
129027
+ if (domPos >= range2.pmStart && domPos <= range2.pmEnd) {
129028
+ lineIndex = li2;
129029
+ break;
129030
+ }
128639
129031
  }
128640
129032
  }
128641
129033
  }
@@ -136826,9 +137218,14 @@ class HeaderFooterSessionManager {
136826
137218
  var SUBSCRIPT_SUPERSCRIPT_SCALE2 = 0.65;
136827
137219
  var DEFAULT_PAGE_SIZE = { w: 612, h: 792 };
136828
137220
  var DEFAULT_MARGINS = { top: 72, right: 72, bottom: 72, left: 72 };
136829
- var DEFAULT_VIRTUALIZED_PAGE_GAP = 72;
136830
137221
  var DEFAULT_PAGE_GAP = 24;
136831
137222
  var DEFAULT_HORIZONTAL_PAGE_GAP = 20;
137223
+ var layoutDebugEnabled = typeof process$1 !== "undefined" && typeof process$1.env !== "undefined" && Boolean(process$1.env.SD_DEBUG_LAYOUT);
137224
+ var perfLog = (...args2) => {
137225
+ if (!layoutDebugEnabled)
137226
+ return;
137227
+ console.log(...args2);
137228
+ };
136832
137229
  var HEADER_FOOTER_INIT_BUDGET_MS = 200;
136833
137230
  var MAX_ZOOM_WARNING_THRESHOLD = 10;
136834
137231
  var MAX_SELECTION_RECTS_PER_USER = 100;
@@ -136876,6 +137273,8 @@ class PresentationEditor extends EventEmitter2 {
136876
137273
  #hiddenHost;
136877
137274
  #layoutOptions;
136878
137275
  #layoutState = { blocks: [], measures: [], layout: null, bookmarks: /* @__PURE__ */ new Map };
137276
+ #flowBlockCache = new FlowBlockCache;
137277
+ #footnoteNumberSignature = null;
136879
137278
  #domPainter = null;
136880
137279
  #pageGeometryHelper = null;
136881
137280
  #dragDropManager = null;
@@ -136897,6 +137296,8 @@ class PresentationEditor extends EventEmitter2 {
136897
137296
  #domIndexObserverManager = null;
136898
137297
  #rafHandle = null;
136899
137298
  #editorListeners = [];
137299
+ #scrollHandler = null;
137300
+ #scrollContainer = null;
136900
137301
  #sectionMetadata = [];
136901
137302
  #documentMode = "editing";
136902
137303
  #inputBridge = null;
@@ -137278,6 +137679,7 @@ class PresentationEditor extends EventEmitter2 {
137278
137679
  this.#syncHiddenEditorA11yAttributes();
137279
137680
  const trackedChangesChanged = this.#syncTrackedChangesPreferences();
137280
137681
  if (modeChanged || trackedChangesChanged) {
137682
+ this.#flowBlockCache.clear();
137281
137683
  this.#pendingDocChange = true;
137282
137684
  this.#scheduleRerender();
137283
137685
  }
@@ -137305,6 +137707,7 @@ class PresentationEditor extends EventEmitter2 {
137305
137707
  this.#layoutOptions.trackedChanges = overrides;
137306
137708
  const trackedChangesChanged = this.#syncTrackedChangesPreferences();
137307
137709
  if (trackedChangesChanged) {
137710
+ this.#flowBlockCache.clear();
137308
137711
  this.#pendingDocChange = true;
137309
137712
  this.#scheduleRerender();
137310
137713
  }
@@ -137327,6 +137730,7 @@ class PresentationEditor extends EventEmitter2 {
137327
137730
  }
137328
137731
  }
137329
137732
  if (hasChanges) {
137733
+ this.#flowBlockCache.clear();
137330
137734
  this.#pendingDocChange = true;
137331
137735
  this.#scheduleRerender();
137332
137736
  }
@@ -137918,6 +138322,15 @@ class PresentationEditor extends EventEmitter2 {
137918
138322
  this.#editorInputManager = null;
137919
138323
  }, "Editor input manager");
137920
138324
  }
138325
+ if (this.#scrollHandler) {
138326
+ if (this.#scrollContainer) {
138327
+ this.#scrollContainer.removeEventListener("scroll", this.#scrollHandler);
138328
+ }
138329
+ const win = this.#visibleHost?.ownerDocument?.defaultView;
138330
+ win?.removeEventListener("scroll", this.#scrollHandler);
138331
+ this.#scrollHandler = null;
138332
+ this.#scrollContainer = null;
138333
+ }
137921
138334
  this.#inputBridge?.notifyTargetChanged();
137922
138335
  this.#inputBridge?.destroy();
137923
138336
  this.#inputBridge = null;
@@ -137932,6 +138345,7 @@ class PresentationEditor extends EventEmitter2 {
137932
138345
  this.#headerFooterSession?.destroy();
137933
138346
  this.#headerFooterSession = null;
137934
138347
  }, "Header/footer session manager");
138348
+ this.#flowBlockCache.clear();
137935
138349
  this.#domPainter = null;
137936
138350
  this.#pageGeometryHelper = null;
137937
138351
  this.#dragDropManager?.destroy();
@@ -138125,6 +138539,32 @@ class PresentationEditor extends EventEmitter2 {
138125
138539
  }
138126
138540
  #setupPointerHandlers() {
138127
138541
  this.#editorInputManager?.bind();
138542
+ this.#scrollHandler = () => {
138543
+ this.#domPainter?.onScroll?.();
138544
+ };
138545
+ this.#scrollContainer = this.#findScrollableAncestor(this.#visibleHost);
138546
+ if (this.#scrollContainer) {
138547
+ this.#scrollContainer.addEventListener("scroll", this.#scrollHandler, { passive: true });
138548
+ }
138549
+ const win = this.#visibleHost.ownerDocument?.defaultView;
138550
+ if (win && this.#scrollContainer !== win) {
138551
+ win.addEventListener("scroll", this.#scrollHandler, { passive: true });
138552
+ }
138553
+ }
138554
+ #findScrollableAncestor(element3) {
138555
+ const win = element3.ownerDocument?.defaultView;
138556
+ if (!win)
138557
+ return null;
138558
+ let current = element3;
138559
+ while (current) {
138560
+ const style2 = win.getComputedStyle(current);
138561
+ const overflowY = style2.overflowY;
138562
+ if (overflowY === "auto" || overflowY === "scroll") {
138563
+ return current;
138564
+ }
138565
+ current = current.parentElement;
138566
+ }
138567
+ return win;
138128
138568
  }
138129
138569
  #setupDragHandlers() {
138130
138570
  this.#dragDropManager?.destroy();
@@ -138324,9 +138764,13 @@ class PresentationEditor extends EventEmitter2 {
138324
138764
  let docJson;
138325
138765
  const viewWindow = this.#visibleHost.ownerDocument?.defaultView ?? window;
138326
138766
  const perf2 = viewWindow?.performance ?? GLOBAL_PERFORMANCE;
138767
+ const perfNow2 = () => perf2?.now ? perf2.now() : Date.now();
138327
138768
  const startMark = perf2?.now?.();
138328
138769
  try {
138770
+ const getJsonStart = perfNow2();
138329
138771
  docJson = this.#editor.getJSON();
138772
+ const getJsonEnd = perfNow2();
138773
+ perfLog(`[Perf] getJSON: ${(getJsonEnd - getJsonStart).toFixed(2)}ms`);
138330
138774
  } catch (error) {
138331
138775
  this.#handleLayoutError("render", this.#decorateError(error, "getJSON"));
138332
138776
  return;
@@ -138339,6 +138783,7 @@ class PresentationEditor extends EventEmitter2 {
138339
138783
  try {
138340
138784
  const converter2 = this.#editor.converter;
138341
138785
  const footnoteNumberById = {};
138786
+ const footnoteOrder = [];
138342
138787
  try {
138343
138788
  const seen = /* @__PURE__ */ new Set;
138344
138789
  let counter = 1;
@@ -138353,9 +138798,19 @@ class PresentationEditor extends EventEmitter2 {
138353
138798
  return;
138354
138799
  seen.add(key2);
138355
138800
  footnoteNumberById[key2] = counter;
138801
+ footnoteOrder.push(key2);
138356
138802
  counter += 1;
138357
138803
  });
138358
- } catch {}
138804
+ } catch (e) {
138805
+ if (typeof console !== "undefined" && console.warn) {
138806
+ console.warn("[PresentationEditor] Failed to compute footnote numbering:", e);
138807
+ }
138808
+ }
138809
+ const footnoteSignature = footnoteOrder.join("|");
138810
+ if (footnoteSignature !== this.#footnoteNumberSignature) {
138811
+ this.#flowBlockCache.clear();
138812
+ this.#footnoteNumberSignature = footnoteSignature;
138813
+ }
138359
138814
  try {
138360
138815
  if (converter2 && typeof converter2 === "object") {
138361
138816
  converter2["footnoteNumberById"] = footnoteNumberById;
@@ -138368,8 +138823,12 @@ class PresentationEditor extends EventEmitter2 {
138368
138823
  translatedNumbering: converter2.translatedNumbering
138369
138824
  } : undefined;
138370
138825
  const atomNodeTypes = getAtomNodeTypes(this.#editor?.schema ?? null);
138826
+ const positionMapStart = perfNow2();
138371
138827
  const positionMap = this.#editor?.state?.doc && docJson ? buildPositionMapFromPmDoc(this.#editor.state.doc, docJson) : null;
138828
+ const positionMapEnd = perfNow2();
138829
+ perfLog(`[Perf] buildPositionMapFromPmDoc: ${(positionMapEnd - positionMapStart).toFixed(2)}ms`);
138372
138830
  const commentsEnabled = this.#documentMode !== "viewing" || this.#layoutOptions.enableCommentsInViewing === true;
138831
+ const toFlowBlocksStart = perfNow2();
138373
138832
  const result = toFlowBlocks(docJson, {
138374
138833
  mediaFiles: this.#editor?.storage?.image?.media,
138375
138834
  emitSectionBreaks: true,
@@ -138380,9 +138839,12 @@ class PresentationEditor extends EventEmitter2 {
138380
138839
  enableRichHyperlinks: true,
138381
138840
  themeColors: this.#editor?.converter?.themeColors ?? undefined,
138382
138841
  converterContext,
138842
+ flowBlockCache: this.#flowBlockCache,
138383
138843
  ...positionMap ? { positions: positionMap } : {},
138384
138844
  ...atomNodeTypes.length > 0 ? { atomNodeTypes } : {}
138385
138845
  });
138846
+ const toFlowBlocksEnd = perfNow2();
138847
+ perfLog(`[Perf] toFlowBlocks: ${(toFlowBlocksEnd - toFlowBlocksStart).toFixed(2)}ms (blocks=${result.blocks.length})`);
138386
138848
  blocks2 = result.blocks;
138387
138849
  bookmarks = result.bookmarks ?? /* @__PURE__ */ new Map;
138388
138850
  } catch (error) {
@@ -138399,6 +138861,7 @@ class PresentationEditor extends EventEmitter2 {
138399
138861
  const layoutOptions = footnotesLayoutInput ? { ...baseLayoutOptions, footnotes: footnotesLayoutInput } : baseLayoutOptions;
138400
138862
  const previousBlocks = this.#layoutState.blocks;
138401
138863
  const previousLayout = this.#layoutState.layout;
138864
+ const previousMeasures = this.#layoutState.measures;
138402
138865
  let layout;
138403
138866
  let measures;
138404
138867
  let headerLayouts;
@@ -138407,7 +138870,10 @@ class PresentationEditor extends EventEmitter2 {
138407
138870
  let extraMeasures;
138408
138871
  const headerFooterInput = this.#buildHeaderFooterInput();
138409
138872
  try {
138410
- const result = await incrementalLayout(previousBlocks, previousLayout, blocks2, layoutOptions, (block, constraints) => measureBlock(block, constraints), headerFooterInput ?? undefined);
138873
+ const incrementalLayoutStart = perfNow2();
138874
+ const result = await incrementalLayout(previousBlocks, previousLayout, blocks2, layoutOptions, (block, constraints) => measureBlock(block, constraints), headerFooterInput ?? undefined, previousMeasures);
138875
+ const incrementalLayoutEnd = perfNow2();
138876
+ perfLog(`[Perf] incrementalLayout: ${(incrementalLayoutEnd - incrementalLayoutStart).toFixed(2)}ms`);
138411
138877
  if (!result || typeof result !== "object") {
138412
138878
  this.#handleLayoutError("render", new Error("incrementalLayout returned invalid result"));
138413
138879
  return;
@@ -138497,14 +138963,23 @@ class PresentationEditor extends EventEmitter2 {
138497
138963
  footerBlocks.push(...extraBlocks);
138498
138964
  footerMeasures.push(...extraMeasures);
138499
138965
  }
138966
+ const painterSetDataStart = perfNow2();
138500
138967
  painter.setData?.(blocks2, measures, headerBlocks.length > 0 ? headerBlocks : undefined, headerMeasures.length > 0 ? headerMeasures : undefined, footerBlocks.length > 0 ? footerBlocks : undefined, footerMeasures.length > 0 ? footerMeasures : undefined);
138968
+ const painterSetDataEnd = perfNow2();
138969
+ perfLog(`[Perf] painter.setData: ${(painterSetDataEnd - painterSetDataStart).toFixed(2)}ms`);
138501
138970
  this.#domIndexObserverManager?.pause();
138502
138971
  const mapping = this.#pendingMapping;
138503
138972
  this.#pendingMapping = null;
138973
+ const painterPaintStart = perfNow2();
138504
138974
  painter.paint(layout, this.#painterHost, mapping ?? undefined);
138975
+ const painterPaintEnd = perfNow2();
138976
+ perfLog(`[Perf] painter.paint: ${(painterPaintEnd - painterPaintStart).toFixed(2)}ms`);
138977
+ const painterPostStart = perfNow2();
138505
138978
  this.#applyVertAlignToLayout();
138506
138979
  this.#rebuildDomPositionIndex();
138507
138980
  this.#domIndexObserverManager?.resume();
138981
+ const painterPostEnd = perfNow2();
138982
+ perfLog(`[Perf] painter.postPaint: ${(painterPostEnd - painterPostStart).toFixed(2)}ms`);
138508
138983
  this.#layoutEpoch = layoutEpoch;
138509
138984
  if (this.#updateHtmlAnnotationMeasurements(layoutEpoch)) {
138510
138985
  this.#pendingDocChange = true;
@@ -139160,7 +139635,7 @@ class PresentationEditor extends EventEmitter2 {
139160
139635
  }
139161
139636
  #getEffectivePageGap() {
139162
139637
  if (this.#layoutOptions.virtualization?.enabled) {
139163
- return Math.max(0, this.#layoutOptions.virtualization.gap ?? DEFAULT_VIRTUALIZED_PAGE_GAP);
139638
+ return Math.max(0, this.#layoutOptions.virtualization.gap ?? DEFAULT_PAGE_GAP);
139164
139639
  }
139165
139640
  if (this.#layoutOptions.layoutMode === "horizontal") {
139166
139641
  return DEFAULT_HORIZONTAL_PAGE_GAP;
@@ -141592,8 +142067,7 @@ var getHTMLFromNode = (node2, editor) => {
141592
142067
  const container = tempDocument.createElement("div");
141593
142068
  const fragment = DOMSerializer.fromSchema(editor.schema).serializeFragment(node2.content);
141594
142069
  container.appendChild(fragment);
141595
- let html3 = container.innerHTML;
141596
- return html3;
142070
+ return container.innerHTML;
141597
142071
  };
141598
142072
  var exportSectionsToJSON = (editor) => {
141599
142073
  const sections = getAllSections(editor);
@@ -141622,10 +142096,14 @@ var getLinkedSectionEditor = (id2, options, editor) => {
141622
142096
  const child = editor.createChildEditor({
141623
142097
  ...options,
141624
142098
  onUpdate: ({ editor: childEditor, transaction }) => {
141625
- const isFromtLinkedParent = transaction.getMeta("fromLinkedParent");
141626
- if (isFromtLinkedParent)
142099
+ const isFromLinkedParent = transaction.getMeta("fromLinkedParent");
142100
+ if (isFromLinkedParent)
141627
142101
  return;
141628
- const updatedContent = childEditor.state.doc.content;
142102
+ const childDocJson = childEditor.state.doc.toJSON();
142103
+ const updatedContent = editor.schema.nodeFromJSON({
142104
+ type: "doc",
142105
+ content: childDocJson.content ?? []
142106
+ }).content;
141629
142107
  const sectionNode = getAllSections(editor)?.find((s2) => s2.node.attrs.id === id2);
141630
142108
  if (!sectionNode)
141631
142109
  return;
@@ -143313,6 +143791,7 @@ function createNumberingManager() {
143313
143791
  }
143314
143792
  function createNumberingPlugin(editor) {
143315
143793
  const numberingManager = createNumberingManager();
143794
+ let forceFullRecompute = false;
143316
143795
  const applyStartSettingsFromDefinitions = (definitionsMap) => {
143317
143796
  Object.entries(definitionsMap || {}).forEach(([numId, levels]) => {
143318
143797
  Object.entries(levels || {}).forEach(([level, def2]) => {
@@ -143328,6 +143807,7 @@ function createNumberingPlugin(editor) {
143328
143807
  const refreshStartSettings = () => {
143329
143808
  const definitions = ListHelpers.getAllListDefinitions(editor);
143330
143809
  applyStartSettingsFromDefinitions(definitions);
143810
+ forceFullRecompute = true;
143331
143811
  };
143332
143812
  refreshStartSettings();
143333
143813
  if (typeof editor?.on === "function") {
@@ -143344,13 +143824,141 @@ function createNumberingPlugin(editor) {
143344
143824
  name: "numberingPlugin",
143345
143825
  key: new PluginKey("numberingPlugin"),
143346
143826
  appendTransaction(transactions, oldState, newState) {
143827
+ const getParagraphAnchor = ($pos) => {
143828
+ for (let depth = $pos.depth;depth >= 0; depth--) {
143829
+ const node2 = $pos.node(depth);
143830
+ if (node2.type.name === "paragraph") {
143831
+ return depth === 0 ? 0 : $pos.before(depth);
143832
+ }
143833
+ }
143834
+ return null;
143835
+ };
143836
+ const isInlineOnlyChange = (tr2) => {
143837
+ if (!tr2.docChanged)
143838
+ return true;
143839
+ let inlineOnly = true;
143840
+ const baseDoc = tr2.before ?? oldState?.doc ?? newState?.doc;
143841
+ tr2.steps.forEach((step) => {
143842
+ if (!inlineOnly)
143843
+ return;
143844
+ if (step instanceof AddMarkStep || step instanceof RemoveMarkStep) {
143845
+ return;
143846
+ }
143847
+ if (step instanceof ReplaceStep || step instanceof ReplaceAroundStep2) {
143848
+ const { from: from3, to } = step;
143849
+ if (from3 == null || to == null || !baseDoc) {
143850
+ inlineOnly = false;
143851
+ return;
143852
+ }
143853
+ if (from3 < 0 || to < 0 || from3 > baseDoc.content.size || to > baseDoc.content.size) {
143854
+ inlineOnly = false;
143855
+ return;
143856
+ }
143857
+ let $from;
143858
+ let $to;
143859
+ try {
143860
+ $from = baseDoc.resolve(from3);
143861
+ $to = baseDoc.resolve(to);
143862
+ } catch {
143863
+ inlineOnly = false;
143864
+ return;
143865
+ }
143866
+ const fromPara = getParagraphAnchor($from);
143867
+ const toPara = getParagraphAnchor($to);
143868
+ if (fromPara == null || toPara == null || fromPara !== toPara) {
143869
+ inlineOnly = false;
143870
+ return;
143871
+ }
143872
+ if (step.slice?.content) {
143873
+ let hasBlock = false;
143874
+ step.slice.content.descendants((node2) => {
143875
+ if (node2.isBlock) {
143876
+ hasBlock = true;
143877
+ return false;
143878
+ }
143879
+ return;
143880
+ });
143881
+ if (hasBlock) {
143882
+ inlineOnly = false;
143883
+ }
143884
+ }
143885
+ return;
143886
+ }
143887
+ inlineOnly = false;
143888
+ });
143889
+ return inlineOnly;
143890
+ };
143347
143891
  const isFromPlugin = transactions.some((tr2) => tr2.getMeta("orderedListSync"));
143348
143892
  const forcePluginPass = transactions.some((tr2) => tr2.getMeta("forcePluginPass"));
143349
- if (isFromPlugin || !forcePluginPass && !transactions.some((tr2) => tr2.docChanged)) {
143893
+ const hasDocChanges = transactions.some((tr2) => tr2.docChanged);
143894
+ if (isFromPlugin || !forcePluginPass && !forceFullRecompute && !hasDocChanges) {
143350
143895
  return null;
143351
143896
  }
143897
+ if (!forcePluginPass && !forceFullRecompute) {
143898
+ const inlineOnly = transactions.every((tr2) => isInlineOnlyChange(tr2));
143899
+ if (inlineOnly) {
143900
+ return null;
143901
+ }
143902
+ }
143903
+ const hasNumberedParagraphInRange = (doc22, from3, to) => {
143904
+ if (!doc22 || from3 == null || to == null)
143905
+ return false;
143906
+ const docSize = doc22.content.size;
143907
+ const rangeStart = Math.max(0, Math.min(from3, to));
143908
+ const rangeEnd = Math.min(docSize, Math.max(from3, to));
143909
+ let found2 = false;
143910
+ doc22.nodesBetween(rangeStart, rangeEnd, (node2, pos) => {
143911
+ if (found2)
143912
+ return false;
143913
+ if (node2.type.name !== "paragraph")
143914
+ return;
143915
+ const resolvedProps = calculateResolvedParagraphProperties(editor, node2, doc22.resolve(pos));
143916
+ if (resolvedProps?.numberingProperties) {
143917
+ found2 = true;
143918
+ return false;
143919
+ }
143920
+ return false;
143921
+ });
143922
+ return found2;
143923
+ };
143924
+ const shouldRecompute = (() => {
143925
+ if (forcePluginPass || forceFullRecompute)
143926
+ return true;
143927
+ if (!hasDocChanges)
143928
+ return false;
143929
+ const diffStart = oldState.doc.content.findDiffStart(newState.doc.content);
143930
+ if (diffStart == null)
143931
+ return false;
143932
+ const diffEnd = oldState.doc.content.findDiffEnd(newState.doc.content);
143933
+ const oldDiffEnd = diffEnd?.a ?? diffStart;
143934
+ const newDiffEnd = diffEnd?.b ?? diffStart;
143935
+ const oldHasList = hasNumberedParagraphInRange(oldState.doc, diffStart, oldDiffEnd);
143936
+ if (oldHasList)
143937
+ return true;
143938
+ const newHasList = hasNumberedParagraphInRange(newState.doc, diffStart, newDiffEnd);
143939
+ return newHasList;
143940
+ })();
143941
+ if (!shouldRecompute) {
143942
+ return null;
143943
+ }
143944
+ forceFullRecompute = false;
143352
143945
  const tr = newState.tr;
143353
143946
  tr.setMeta("orderedListSync", true);
143947
+ const bumpBlockRev = (node2, pos) => {
143948
+ const current = node2?.attrs?.sdBlockRev;
143949
+ let nextRev;
143950
+ if (typeof current === "number" && Number.isFinite(current)) {
143951
+ nextRev = current + 1;
143952
+ } else if (typeof current === "string" && current.trim() !== "") {
143953
+ const parsed = Number.parseInt(current, 10);
143954
+ if (Number.isFinite(parsed)) {
143955
+ nextRev = parsed + 1;
143956
+ }
143957
+ }
143958
+ if (nextRev != null) {
143959
+ tr.setNodeAttribute(pos, "sdBlockRev", nextRev);
143960
+ }
143961
+ };
143354
143962
  numberingManager.enableCache();
143355
143963
  newState.doc.descendants((node2, pos) => {
143356
143964
  let resolvedProps = calculateResolvedParagraphProperties(editor, node2, newState.doc.resolve(pos));
@@ -143361,6 +143969,7 @@ function createNumberingPlugin(editor) {
143361
143969
  const definitionDetails = ListHelpers.getListDefinitionDetails({ numId, level, editor });
143362
143970
  if (!definitionDetails || Object.keys(definitionDetails).length === 0) {
143363
143971
  tr.setNodeAttribute(pos, "listRendering", null);
143972
+ bumpBlockRev(node2, pos);
143364
143973
  return;
143365
143974
  }
143366
143975
  let { lvlText, customFormat, listNumberingType, suffix: suffix2, justification, abstractId } = definitionDetails;
@@ -143388,6 +143997,7 @@ function createNumberingPlugin(editor) {
143388
143997
  };
143389
143998
  if (JSON.stringify(node2.attrs.listRendering) !== JSON.stringify(newListRendering)) {
143390
143999
  tr.setNodeAttribute(pos, "listRendering", newListRendering);
144000
+ bumpBlockRev(node2, pos);
143391
144001
  }
143392
144002
  return false;
143393
144003
  });
@@ -143481,10 +144091,16 @@ function createDropcapPlugin(editor) {
143481
144091
  key: new PluginKey("dropcapPlugin"),
143482
144092
  state: {
143483
144093
  init(_22, state2) {
144094
+ if (editor.presentationEditor) {
144095
+ return DecorationSet.empty;
144096
+ }
143484
144097
  const decorations = getDropcapDecorations(state2, view, dropcapWidthCache);
143485
144098
  return DecorationSet.create(state2.doc, decorations);
143486
144099
  },
143487
144100
  apply(tr, oldDecorationSet, oldState, newState) {
144101
+ if (editor.presentationEditor) {
144102
+ return DecorationSet.empty;
144103
+ }
143488
144104
  if (!tr.docChanged)
143489
144105
  return oldDecorationSet;
143490
144106
  let hasDropcaps = false;
@@ -143630,6 +144246,11 @@ var Paragraph = OxmlNode.create({
143630
144246
  return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
143631
144247
  }
143632
144248
  },
144249
+ sdBlockRev: {
144250
+ default: 0,
144251
+ rendered: false,
144252
+ keepOnSplit: false
144253
+ },
143633
144254
  attributes: {
143634
144255
  rendered: false
143635
144256
  },
@@ -144332,17 +144953,24 @@ var TabNode = Node$12.create({
144332
144953
  if (isHeadless(this.editor)) {
144333
144954
  return [];
144334
144955
  }
144335
- const { view, helpers: helpers2 } = this.editor;
144956
+ const editor = this.editor;
144957
+ const { view, helpers: helpers2 } = editor;
144336
144958
  const tabPlugin = new Plugin({
144337
144959
  name: "tabPlugin",
144338
144960
  key: new PluginKey("tabPlugin"),
144339
144961
  state: {
144340
144962
  init() {
144963
+ if (editor.presentationEditor) {
144964
+ return { decorations: DecorationSet.empty, revision: 0 };
144965
+ }
144341
144966
  const initialDecorations = buildInitialDecorations(view.state.doc, view, helpers2, 0);
144342
144967
  return { decorations: initialDecorations, revision: 0 };
144343
144968
  },
144344
144969
  apply(tr, { decorations, revision }, _oldState, newState) {
144345
144970
  const currentDecorations = decorations && decorations.map ? decorations.map(tr.mapping, tr.doc) : DecorationSet.empty;
144971
+ if (editor.presentationEditor) {
144972
+ return { decorations: DecorationSet.empty, revision };
144973
+ }
144346
144974
  if (!tr.docChanged || tr.getMeta("blockNodeInitialUpdate")) {
144347
144975
  return { decorations: currentDecorations, revision };
144348
144976
  }
@@ -144408,6 +145036,16 @@ function buildInitialDecorations(doc22, view, helpers2, revision) {
144408
145036
  return DecorationSet.create(doc22, decorations);
144409
145037
  }
144410
145038
  function buildParagraphDecorations(doc22, paragraphContentPos, paragraphNode, view, helpers2, revision) {
145039
+ let hasTab = false;
145040
+ paragraphNode.descendants((child) => {
145041
+ if (child.type.name === "tab") {
145042
+ hasTab = true;
145043
+ return false;
145044
+ }
145045
+ return true;
145046
+ });
145047
+ if (!hasTab)
145048
+ return [];
144411
145049
  const request = createLayoutRequest(doc22, paragraphContentPos, view, helpers2, revision);
144412
145050
  if (!request)
144413
145051
  return [];
@@ -149308,6 +149946,7 @@ var ContentBlock = Node$12.create({
149308
149946
  });
149309
149947
  var { findChildren } = helpers;
149310
149948
  var SD_BLOCK_ID_ATTRIBUTE_NAME = "sdBlockId";
149949
+ var SD_BLOCK_REV_ATTRIBUTE_NAME = "sdBlockRev";
149311
149950
  var BlockNodePluginKey = new PluginKey("blockNodePlugin");
149312
149951
  var BlockNode = Extension.create({
149313
149952
  name: "blockNode",
@@ -149392,11 +150031,26 @@ var BlockNode = Extension.create({
149392
150031
  },
149393
150032
  addPmPlugins() {
149394
150033
  let hasInitialized = false;
149395
- const assignBlockId = (tr, node2, pos) => {
149396
- tr.setNodeMarkup(pos, undefined, {
149397
- ...node2.attrs,
149398
- sdBlockId: v4()
149399
- }, node2.marks);
150034
+ const getNextBlockRev = (node2) => {
150035
+ const current = node2?.attrs?.[SD_BLOCK_REV_ATTRIBUTE_NAME];
150036
+ if (typeof current === "number" && Number.isFinite(current))
150037
+ return current + 1;
150038
+ const parsed = Number.parseInt(current, 10);
150039
+ if (Number.isFinite(parsed))
150040
+ return parsed + 1;
150041
+ return 1;
150042
+ };
150043
+ const ensureBlockRev = (node2) => {
150044
+ const current = node2?.attrs?.[SD_BLOCK_REV_ATTRIBUTE_NAME];
150045
+ if (typeof current === "number" && Number.isFinite(current))
150046
+ return current;
150047
+ const parsed = Number.parseInt(current, 10);
150048
+ if (Number.isFinite(parsed))
150049
+ return parsed;
150050
+ return 0;
150051
+ };
150052
+ const applyNodeAttrs = (tr, node2, pos, nextAttrs) => {
150053
+ tr.setNodeMarkup(pos, undefined, nextAttrs, node2.marks);
149400
150054
  };
149401
150055
  return [
149402
150056
  new Plugin({
@@ -149406,15 +150060,28 @@ var BlockNode = Extension.create({
149406
150060
  if (hasInitialized && !docChanges) {
149407
150061
  return;
149408
150062
  }
149409
- if (hasInitialized && !checkForNewBlockNodesInTrs([...transactions])) {
149410
- return;
149411
- }
149412
150063
  const { tr } = newState;
149413
150064
  let changed = false;
150065
+ const updatedPositions = /* @__PURE__ */ new Set;
149414
150066
  if (!hasInitialized) {
149415
150067
  newState.doc.descendants((node2, pos) => {
150068
+ if (!nodeAllowsSdBlockIdAttr(node2) && !nodeAllowsSdBlockRevAttr(node2))
150069
+ return;
150070
+ const nextAttrs = { ...node2.attrs };
150071
+ let nodeChanged = false;
149416
150072
  if (nodeAllowsSdBlockIdAttr(node2) && nodeNeedsSdBlockId(node2)) {
149417
- assignBlockId(tr, node2, pos);
150073
+ nextAttrs.sdBlockId = v4();
150074
+ nodeChanged = true;
150075
+ }
150076
+ if (nodeAllowsSdBlockRevAttr(node2)) {
150077
+ const rev = ensureBlockRev(node2);
150078
+ if (nextAttrs.sdBlockRev !== rev) {
150079
+ nextAttrs.sdBlockRev = rev;
150080
+ nodeChanged = true;
150081
+ }
150082
+ }
150083
+ if (nodeChanged) {
150084
+ applyNodeAttrs(tr, node2, pos, nextAttrs);
149418
150085
  changed = true;
149419
150086
  }
149420
150087
  });
@@ -149423,22 +150090,24 @@ var BlockNode = Extension.create({
149423
150090
  let shouldFallbackToFullTraversal = false;
149424
150091
  transactions.forEach((transaction, txIndex) => {
149425
150092
  transaction.steps.forEach((step, stepIndex) => {
149426
- if (!(step instanceof ReplaceStep))
149427
- return;
149428
- const hasNewBlockNodes = step.slice?.content?.content?.some((node2) => nodeAllowsSdBlockIdAttr(node2));
149429
- if (!hasNewBlockNodes)
149430
- return;
149431
- const stepMap = step.getMap();
149432
- stepMap.forEach((_oldStart, _oldEnd, newStart, newEnd) => {
149433
- if (newEnd <= newStart) {
149434
- if (process$1.env.NODE_ENV === "development") {
149435
- console.debug("Block node: invalid range in step map, falling back to full traversal");
150093
+ const stepRanges = [];
150094
+ if (step instanceof ReplaceStep || step instanceof ReplaceAroundStep2) {
150095
+ const stepMap = step.getMap();
150096
+ stepMap.forEach((_oldStart, _oldEnd, newStart, newEnd) => {
150097
+ if (newEnd <= newStart) {
150098
+ stepRanges.push([newStart, newStart + 1]);
150099
+ return;
149436
150100
  }
149437
- shouldFallbackToFullTraversal = true;
149438
- return;
150101
+ stepRanges.push([newStart, newEnd]);
150102
+ });
150103
+ } else if (step instanceof AddMarkStep || step instanceof RemoveMarkStep) {
150104
+ if (step.to > step.from) {
150105
+ stepRanges.push([step.from, step.to]);
149439
150106
  }
149440
- let rangeStart = newStart;
149441
- let rangeEnd = newEnd;
150107
+ }
150108
+ stepRanges.forEach(([rangeStartRaw, rangeEndRaw]) => {
150109
+ let rangeStart = rangeStartRaw;
150110
+ let rangeEnd = rangeEndRaw;
149442
150111
  for (let i3 = stepIndex + 1;i3 < transaction.steps.length; i3++) {
149443
150112
  const laterStepMap = transaction.steps[i3].getMap();
149444
150113
  rangeStart = laterStepMap.map(rangeStart, -1);
@@ -149450,11 +150119,7 @@ var BlockNode = Extension.create({
149450
150119
  rangeEnd = laterTx.mapping.map(rangeEnd, 1);
149451
150120
  }
149452
150121
  if (rangeEnd <= rangeStart) {
149453
- if (process$1.env.NODE_ENV === "development") {
149454
- console.debug("Block node: invalid range after mapping, falling back to full traversal");
149455
- }
149456
- shouldFallbackToFullTraversal = true;
149457
- return;
150122
+ rangeEnd = rangeStart + 1;
149458
150123
  }
149459
150124
  rangesToCheck.push([rangeStart, rangeEnd]);
149460
150125
  });
@@ -149465,17 +150130,28 @@ var BlockNode = Extension.create({
149465
150130
  const docSize = newState.doc.content.size;
149466
150131
  const clampedRange = clampRange(start2, end2, docSize);
149467
150132
  if (!clampedRange) {
149468
- if (process$1.env.NODE_ENV === "development") {
149469
- console.debug("Block node: invalid range after clamping, falling back to full traversal");
149470
- }
149471
- shouldFallbackToFullTraversal = true;
149472
- break;
150133
+ continue;
149473
150134
  }
149474
150135
  const [safeStart, safeEnd] = clampedRange;
149475
150136
  try {
149476
150137
  newState.doc.nodesBetween(safeStart, safeEnd, (node2, pos) => {
150138
+ if (!nodeAllowsSdBlockIdAttr(node2) && !nodeAllowsSdBlockRevAttr(node2))
150139
+ return;
150140
+ if (updatedPositions.has(pos))
150141
+ return;
150142
+ const nextAttrs = { ...node2.attrs };
150143
+ let nodeChanged = false;
149477
150144
  if (nodeAllowsSdBlockIdAttr(node2) && nodeNeedsSdBlockId(node2)) {
149478
- assignBlockId(tr, node2, pos);
150145
+ nextAttrs.sdBlockId = v4();
150146
+ nodeChanged = true;
150147
+ }
150148
+ if (nodeAllowsSdBlockRevAttr(node2)) {
150149
+ nextAttrs.sdBlockRev = getNextBlockRev(node2);
150150
+ nodeChanged = true;
150151
+ }
150152
+ if (nodeChanged) {
150153
+ applyNodeAttrs(tr, node2, pos, nextAttrs);
150154
+ updatedPositions.add(pos);
149479
150155
  changed = true;
149480
150156
  }
149481
150157
  });
@@ -149487,8 +150163,20 @@ var BlockNode = Extension.create({
149487
150163
  }
149488
150164
  if (shouldFallbackToFullTraversal) {
149489
150165
  newState.doc.descendants((node2, pos) => {
150166
+ if (!nodeAllowsSdBlockIdAttr(node2) && !nodeAllowsSdBlockRevAttr(node2))
150167
+ return;
150168
+ const nextAttrs = { ...node2.attrs };
150169
+ let nodeChanged = false;
149490
150170
  if (nodeAllowsSdBlockIdAttr(node2) && nodeNeedsSdBlockId(node2)) {
149491
- assignBlockId(tr, node2, pos);
150171
+ nextAttrs.sdBlockId = v4();
150172
+ nodeChanged = true;
150173
+ }
150174
+ if (nodeAllowsSdBlockRevAttr(node2)) {
150175
+ nextAttrs.sdBlockRev = getNextBlockRev(node2);
150176
+ nodeChanged = true;
150177
+ }
150178
+ if (nodeChanged) {
150179
+ applyNodeAttrs(tr, node2, pos, nextAttrs);
149492
150180
  changed = true;
149493
150181
  }
149494
150182
  });
@@ -149508,20 +150196,13 @@ var BlockNode = Extension.create({
149508
150196
  var nodeAllowsSdBlockIdAttr = (node2) => {
149509
150197
  return !!(node2?.isBlock && node2?.type?.spec?.attrs?.[SD_BLOCK_ID_ATTRIBUTE_NAME]);
149510
150198
  };
150199
+ var nodeAllowsSdBlockRevAttr = (node2) => {
150200
+ return !!(node2?.isBlock && node2?.type?.spec?.attrs?.[SD_BLOCK_REV_ATTRIBUTE_NAME]);
150201
+ };
149511
150202
  var nodeNeedsSdBlockId = (node2) => {
149512
150203
  const currentId = node2?.attrs?.[SD_BLOCK_ID_ATTRIBUTE_NAME];
149513
150204
  return !currentId;
149514
150205
  };
149515
- var checkForNewBlockNodesInTrs = (transactions) => {
149516
- return Array.from(transactions).some((tr) => {
149517
- return tr.steps.some((step) => {
149518
- if (!(step instanceof ReplaceStep))
149519
- return false;
149520
- const hasValidSdBlockNodes = step.slice?.content?.content?.some((node2) => nodeAllowsSdBlockIdAttr(node2));
149521
- return hasValidSdBlockNodes;
149522
- });
149523
- });
149524
- };
149525
150206
  var TableOfContents = Node$12.create({
149526
150207
  name: "tableOfContents",
149527
150208
  group: "block",
@@ -151681,6 +152362,9 @@ var createLinkedStylesPlugin = (editor) => {
151681
152362
  init() {
151682
152363
  if (!editor.converter || editor.options.mode !== "docx")
151683
152364
  return {};
152365
+ if (editor.presentationEditor) {
152366
+ return { styles: editor.converter?.linkedStyles || [], decorations: DecorationSet.empty };
152367
+ }
151684
152368
  const styles = editor.converter?.linkedStyles || [];
151685
152369
  return {
151686
152370
  styles,
@@ -151690,6 +152374,9 @@ var createLinkedStylesPlugin = (editor) => {
151690
152374
  apply(tr, prev, oldEditorState, newEditorState) {
151691
152375
  if (!editor.converter || editor.options.mode !== "docx")
151692
152376
  return { ...prev };
152377
+ if (editor.presentationEditor) {
152378
+ return { ...prev, decorations: DecorationSet.empty };
152379
+ }
151693
152380
  let decorations = prev.decorations || DecorationSet.empty;
151694
152381
  if (tr.docChanged) {
151695
152382
  let mightAffectStyles = false;
@@ -164432,8 +165119,8 @@ var isArguments2 = baseIsArguments(/* @__PURE__ */ function() {
164432
165119
  function stubFalse() {
164433
165120
  return false;
164434
165121
  }
164435
- var freeExports$2 = typeof exports_index_Cd5b_X9__es == "object" && exports_index_Cd5b_X9__es && !exports_index_Cd5b_X9__es.nodeType && exports_index_Cd5b_X9__es;
164436
- var freeModule$2 = freeExports$2 && typeof module_index_Cd5b_X9__es == "object" && module_index_Cd5b_X9__es && !module_index_Cd5b_X9__es.nodeType && module_index_Cd5b_X9__es;
165122
+ var freeExports$2 = typeof exports_index_CWIntMYO_es == "object" && exports_index_CWIntMYO_es && !exports_index_CWIntMYO_es.nodeType && exports_index_CWIntMYO_es;
165123
+ var freeModule$2 = freeExports$2 && typeof module_index_CWIntMYO_es == "object" && module_index_CWIntMYO_es && !module_index_CWIntMYO_es.nodeType && module_index_CWIntMYO_es;
164437
165124
  var moduleExports$2 = freeModule$2 && freeModule$2.exports === freeExports$2;
164438
165125
  var Buffer$1 = moduleExports$2 ? root3.Buffer : undefined;
164439
165126
  var nativeIsBuffer = Buffer$1 ? Buffer$1.isBuffer : undefined;
@@ -164473,8 +165160,8 @@ function baseUnary(func) {
164473
165160
  return func(value);
164474
165161
  };
164475
165162
  }
164476
- var freeExports$1 = typeof exports_index_Cd5b_X9__es == "object" && exports_index_Cd5b_X9__es && !exports_index_Cd5b_X9__es.nodeType && exports_index_Cd5b_X9__es;
164477
- var freeModule$1 = freeExports$1 && typeof module_index_Cd5b_X9__es == "object" && module_index_Cd5b_X9__es && !module_index_Cd5b_X9__es.nodeType && module_index_Cd5b_X9__es;
165163
+ var freeExports$1 = typeof exports_index_CWIntMYO_es == "object" && exports_index_CWIntMYO_es && !exports_index_CWIntMYO_es.nodeType && exports_index_CWIntMYO_es;
165164
+ var freeModule$1 = freeExports$1 && typeof module_index_CWIntMYO_es == "object" && module_index_CWIntMYO_es && !module_index_CWIntMYO_es.nodeType && module_index_CWIntMYO_es;
164478
165165
  var moduleExports$1 = freeModule$1 && freeModule$1.exports === freeExports$1;
164479
165166
  var freeProcess = moduleExports$1 && freeGlobal.process;
164480
165167
  var nodeUtil = function() {
@@ -164847,8 +165534,8 @@ Stack.prototype["delete"] = stackDelete;
164847
165534
  Stack.prototype.get = stackGet;
164848
165535
  Stack.prototype.has = stackHas;
164849
165536
  Stack.prototype.set = stackSet;
164850
- var freeExports = typeof exports_index_Cd5b_X9__es == "object" && exports_index_Cd5b_X9__es && !exports_index_Cd5b_X9__es.nodeType && exports_index_Cd5b_X9__es;
164851
- var freeModule = freeExports && typeof module_index_Cd5b_X9__es == "object" && module_index_Cd5b_X9__es && !module_index_Cd5b_X9__es.nodeType && module_index_Cd5b_X9__es;
165537
+ var freeExports = typeof exports_index_CWIntMYO_es == "object" && exports_index_CWIntMYO_es && !exports_index_CWIntMYO_es.nodeType && exports_index_CWIntMYO_es;
165538
+ var freeModule = freeExports && typeof module_index_CWIntMYO_es == "object" && module_index_CWIntMYO_es && !module_index_CWIntMYO_es.nodeType && module_index_CWIntMYO_es;
164852
165539
  var moduleExports = freeModule && freeModule.exports === freeExports;
164853
165540
  var Buffer3 = moduleExports ? root3.Buffer : undefined;
164854
165541
  Buffer3 && Buffer3.allocUnsafe;