@harbour-enterprises/superdoc 1.4.1-next.2 → 1.5.0-next.1

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.
@@ -36961,7 +36961,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
36961
36961
  static getStoredSuperdocVersion(docx) {
36962
36962
  return SuperConverter.getStoredCustomProperty(docx, "SuperdocVersion");
36963
36963
  }
36964
- static setStoredSuperdocVersion(docx = this.convertedXml, version2 = "1.4.1-next.2") {
36964
+ static setStoredSuperdocVersion(docx = this.convertedXml, version2 = "1.5.0-next.1") {
36965
36965
  return SuperConverter.setStoredCustomProperty(docx, "SuperdocVersion", version2, false);
36966
36966
  }
36967
36967
  /**
@@ -62836,7 +62836,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
62836
62836
  return false;
62837
62837
  }
62838
62838
  };
62839
- const summaryVersion = "1.4.1-next.2";
62839
+ const summaryVersion = "1.5.0-next.1";
62840
62840
  const nodeKeys = ["group", "content", "marks", "inline", "atom", "defining", "code", "tableRole", "summary"];
62841
62841
  const markKeys = ["group", "inclusive", "excludes", "spanning", "code"];
62842
62842
  function mapAttributes(attrs) {
@@ -64147,6 +64147,31 @@ Please report this to https://github.com/markedjs/marked.`, e) {
64147
64147
  }
64148
64148
  return null;
64149
64149
  }
64150
+ /**
64151
+ * Get the DOM element for a document position.
64152
+ * In presentation mode, returns the painted element.
64153
+ */
64154
+ getElementAtPos(pos, options = {}) {
64155
+ if (this.presentationEditor) {
64156
+ return this.presentationEditor.getElementAtPos(pos, options);
64157
+ }
64158
+ if (!this.view) return null;
64159
+ if (!Number.isFinite(pos)) return null;
64160
+ const maxPos = this.view.state.doc.content.size;
64161
+ const clampedPos = Math.max(0, Math.min(pos, maxPos));
64162
+ try {
64163
+ const { node: node2 } = this.view.domAtPos(clampedPos);
64164
+ if (node2 && node2.nodeType === 1) {
64165
+ return node2;
64166
+ }
64167
+ if (node2 && node2.nodeType === 3) {
64168
+ return node2.parentElement;
64169
+ }
64170
+ return node2?.parentElement ?? null;
64171
+ } catch {
64172
+ return null;
64173
+ }
64174
+ }
64150
64175
  /**
64151
64176
  * Get position from client-space coordinates.
64152
64177
  * In layout/presentation mode, uses PresentationEditor hit testing for accurate coordinate mapping.
@@ -65469,7 +65494,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
65469
65494
  * Process collaboration migrations
65470
65495
  */
65471
65496
  processCollaborationMigrations() {
65472
- console.debug("[checkVersionMigrations] Current editor version", "1.4.1-next.2");
65497
+ console.debug("[checkVersionMigrations] Current editor version", "1.5.0-next.1");
65473
65498
  if (!this.options.ydoc) return;
65474
65499
  const metaMap = this.options.ydoc.getMap("meta");
65475
65500
  let docVersion = metaMap.get("version");
@@ -70493,27 +70518,33 @@ ${l}
70493
70518
  align-items: center;
70494
70519
  }
70495
70520
 
70496
- /* Continuation styling: first fragment has top corners, last has bottom corners */
70497
- .superdoc-document-section[data-sdt-container-start="true"] {
70498
- border-radius: 4px 4px 0 0;
70521
+ /* Continuation styling: SDT container boundary handling for multi-fragment document sections */
70522
+ /* Single fragment (both start and end): full border radius */
70523
+ .superdoc-document-section[data-sdt-container-start="true"][data-sdt-container-end="true"] {
70524
+ border-radius: 4px;
70499
70525
  }
70500
70526
 
70501
- .superdoc-document-section[data-sdt-container-end="true"] {
70502
- border-radius: 0 0 4px 4px;
70527
+ /* First fragment of a multi-fragment SDT: top corners, no bottom border */
70528
+ .superdoc-document-section[data-sdt-container-start="true"]:not([data-sdt-container-end="true"]) {
70529
+ border-radius: 4px 4px 0 0;
70530
+ border-bottom: none;
70503
70531
  }
70504
70532
 
70505
- .superdoc-document-section[data-sdt-container-start="true"][data-sdt-container-end="true"] {
70506
- border-radius: 4px;
70533
+ /* Last fragment of a multi-fragment SDT: bottom corners, no top border */
70534
+ .superdoc-document-section[data-sdt-container-end="true"]:not([data-sdt-container-start="true"]) {
70535
+ border-radius: 0 0 4px 4px;
70536
+ border-top: none;
70507
70537
  }
70508
70538
 
70509
70539
  .superdoc-document-section[data-sdt-container-start="true"]:hover {
70510
70540
  border-radius: 0 4px 0 0;
70511
70541
  }
70512
70542
 
70513
- /* Middle fragments have no border radius */
70543
+ /* Middle fragments (neither start nor end): no corners, no top/bottom borders */
70514
70544
  .superdoc-document-section:not([data-sdt-container-start="true"]):not([data-sdt-container-end="true"]) {
70515
70545
  border-radius: 0;
70516
70546
  border-top: none;
70547
+ border-bottom: none;
70517
70548
  }
70518
70549
 
70519
70550
  /* Structured Content Block - Blue border container */
@@ -70560,21 +70591,28 @@ ${l}
70560
70591
  }
70561
70592
 
70562
70593
  /* Continuation styling for structured content blocks */
70563
- .superdoc-structured-content-block[data-sdt-container-start="true"] {
70564
- border-radius: 4px 4px 0 0;
70594
+ /* Single fragment (both start and end): full border radius */
70595
+ .superdoc-structured-content-block[data-sdt-container-start="true"][data-sdt-container-end="true"] {
70596
+ border-radius: 4px;
70565
70597
  }
70566
70598
 
70567
- .superdoc-structured-content-block[data-sdt-container-end="true"] {
70568
- border-radius: 0 0 4px 4px;
70599
+ /* First fragment of a multi-fragment SDT: top corners, no bottom border */
70600
+ .superdoc-structured-content-block[data-sdt-container-start="true"]:not([data-sdt-container-end="true"]) {
70601
+ border-radius: 4px 4px 0 0;
70602
+ border-bottom: none;
70569
70603
  }
70570
70604
 
70571
- .superdoc-structured-content-block[data-sdt-container-start="true"][data-sdt-container-end="true"] {
70572
- border-radius: 4px;
70605
+ /* Last fragment of a multi-fragment SDT: bottom corners, no top border */
70606
+ .superdoc-structured-content-block[data-sdt-container-end="true"]:not([data-sdt-container-start="true"]) {
70607
+ border-radius: 0 0 4px 4px;
70608
+ border-top: none;
70573
70609
  }
70574
70610
 
70611
+ /* Middle fragment (neither start nor end): no corners, no top/bottom borders */
70575
70612
  .superdoc-structured-content-block:not([data-sdt-container-start="true"]):not([data-sdt-container-end="true"]) {
70576
70613
  border-radius: 0;
70577
70614
  border-top: none;
70615
+ border-bottom: none;
70578
70616
  }
70579
70617
 
70580
70618
  /* Structured Content Inline - Inline wrapper with blue border */
@@ -71044,6 +71082,78 @@ ${l}
71044
71082
  right: borderValueToSpec(isLastCol ? tableBorders?.right : null)
71045
71083
  };
71046
71084
  };
71085
+ function isStructuredContentMetadata(sdt) {
71086
+ return sdt !== null && sdt !== void 0 && typeof sdt === "object" && "type" in sdt && sdt.type === "structuredContent";
71087
+ }
71088
+ function isDocumentSectionMetadata(sdt) {
71089
+ return sdt !== null && sdt !== void 0 && typeof sdt === "object" && "type" in sdt && sdt.type === "documentSection";
71090
+ }
71091
+ function getSdtContainerConfig(sdt) {
71092
+ if (isDocumentSectionMetadata(sdt)) {
71093
+ return {
71094
+ className: "superdoc-document-section",
71095
+ labelText: sdt.title ?? "Document section",
71096
+ labelClassName: "superdoc-document-section__tooltip",
71097
+ isStart: true,
71098
+ isEnd: true
71099
+ };
71100
+ }
71101
+ if (isStructuredContentMetadata(sdt) && sdt.scope === "block") {
71102
+ return {
71103
+ className: "superdoc-structured-content-block",
71104
+ labelText: sdt.alias ?? "Structured content",
71105
+ labelClassName: "superdoc-structured-content__label",
71106
+ isStart: true,
71107
+ isEnd: true
71108
+ };
71109
+ }
71110
+ return null;
71111
+ }
71112
+ function getSdtContainerMetadata(sdt, containerSdt) {
71113
+ if (getSdtContainerConfig(sdt)) return sdt ?? null;
71114
+ if (getSdtContainerConfig(containerSdt)) return containerSdt ?? null;
71115
+ return null;
71116
+ }
71117
+ function getSdtContainerKey(sdt, containerSdt) {
71118
+ const metadata = getSdtContainerMetadata(sdt, containerSdt);
71119
+ if (!metadata) return null;
71120
+ if (metadata.type === "structuredContent") {
71121
+ if (metadata.scope !== "block") return null;
71122
+ if (!metadata.id) {
71123
+ return null;
71124
+ }
71125
+ return `structuredContent:${metadata.id}`;
71126
+ }
71127
+ if (metadata.type === "documentSection") {
71128
+ const sectionId = metadata.id ?? metadata.sdBlockId;
71129
+ if (!sectionId) {
71130
+ return null;
71131
+ }
71132
+ return `documentSection:${sectionId}`;
71133
+ }
71134
+ return null;
71135
+ }
71136
+ function applySdtContainerStyling(doc2, container, sdt, containerSdt, boundaryOptions) {
71137
+ let config2 = getSdtContainerConfig(sdt);
71138
+ if (!config2 && containerSdt) {
71139
+ config2 = getSdtContainerConfig(containerSdt);
71140
+ }
71141
+ if (!config2) return;
71142
+ const isStart = boundaryOptions?.isStart ?? config2.isStart;
71143
+ const isEnd = boundaryOptions?.isEnd ?? config2.isEnd;
71144
+ container.classList.add(config2.className);
71145
+ container.dataset.sdtContainerStart = String(isStart);
71146
+ container.dataset.sdtContainerEnd = String(isEnd);
71147
+ container.style.overflow = "visible";
71148
+ if (isStart) {
71149
+ const labelEl = doc2.createElement("div");
71150
+ labelEl.className = config2.labelClassName;
71151
+ const labelText = doc2.createElement("span");
71152
+ labelText.textContent = config2.labelText;
71153
+ labelEl.appendChild(labelText);
71154
+ container.appendChild(labelEl);
71155
+ }
71156
+ }
71047
71157
  const LIST_MARKER_GAP$3 = 8;
71048
71158
  function renderListMarker(params2) {
71049
71159
  const { doc: doc2, lineEl, markerLayout, markerMeasure, indentLeftPx } = params2;
@@ -71081,6 +71191,54 @@ ${l}
71081
71191
  lineContainer.appendChild(lineEl);
71082
71192
  return lineContainer;
71083
71193
  }
71194
+ const applyInlineStyles = (el, styles) => {
71195
+ Object.entries(styles).forEach(([key2, value]) => {
71196
+ if (value != null && value !== "" && key2 in el.style) {
71197
+ el.style[key2] = String(value);
71198
+ }
71199
+ });
71200
+ };
71201
+ const EMBEDDED_TABLE_VERSION = "embedded-table";
71202
+ const renderEmbeddedTable = (params2) => {
71203
+ const { doc: doc2, table: table2, measure, context, renderLine, renderDrawingContent, applySdtDataset } = params2;
71204
+ const fragment = {
71205
+ kind: "table",
71206
+ blockId: table2.id,
71207
+ fromRow: 0,
71208
+ toRow: table2.rows.length,
71209
+ x: 0,
71210
+ y: 0,
71211
+ width: measure.totalWidth,
71212
+ height: measure.totalHeight
71213
+ };
71214
+ const blockLookup = /* @__PURE__ */ new Map([
71215
+ [
71216
+ table2.id,
71217
+ {
71218
+ block: table2,
71219
+ measure,
71220
+ version: EMBEDDED_TABLE_VERSION
71221
+ }
71222
+ ]
71223
+ ]);
71224
+ const applyFragmentFrame = (el, frag) => {
71225
+ el.style.left = `${frag.x}px`;
71226
+ el.style.top = `${frag.y}px`;
71227
+ el.style.width = `${frag.width}px`;
71228
+ el.dataset.blockId = frag.blockId;
71229
+ };
71230
+ return renderTableFragment({
71231
+ doc: doc2,
71232
+ fragment,
71233
+ context,
71234
+ blockLookup,
71235
+ renderLine,
71236
+ renderDrawingContent,
71237
+ applyFragmentFrame,
71238
+ applySdtDataset,
71239
+ applyStyles: applyInlineStyles
71240
+ });
71241
+ };
71084
71242
  function applyParagraphBordersAndShading(paraWrapper, block) {
71085
71243
  const borders = block.attrs?.borders;
71086
71244
  if (borders) {
@@ -71121,10 +71279,12 @@ ${l}
71121
71279
  cellMeasure,
71122
71280
  cell: cell2,
71123
71281
  borders,
71282
+ useDefaultBorder,
71124
71283
  renderLine,
71125
71284
  renderDrawingContent,
71126
71285
  context,
71127
71286
  applySdtDataset,
71287
+ tableSdt,
71128
71288
  fromLine,
71129
71289
  toLine
71130
71290
  } = deps;
@@ -71148,12 +71308,46 @@ ${l}
71148
71308
  cellEl.style.paddingBottom = `${paddingBottom}px`;
71149
71309
  if (borders) {
71150
71310
  applyCellBorders(cellEl, borders);
71311
+ } else if (useDefaultBorder) {
71312
+ cellEl.style.border = "1px solid rgba(0,0,0,0.6)";
71151
71313
  }
71152
71314
  if (cell2?.attrs?.background) {
71153
71315
  cellEl.style.backgroundColor = cell2.attrs.background;
71154
71316
  }
71155
71317
  const cellBlocks = cell2?.blocks ?? (cell2?.paragraph ? [cell2.paragraph] : []);
71156
71318
  const blockMeasures = cellMeasure?.blocks ?? (cellMeasure?.paragraph ? [cellMeasure.paragraph] : []);
71319
+ const sdtContainerKeys = cellBlocks.map((block) => {
71320
+ if (block.kind !== "paragraph") {
71321
+ return null;
71322
+ }
71323
+ const attrs2 = block.attrs;
71324
+ return getSdtContainerKey(attrs2?.sdt, attrs2?.containerSdt);
71325
+ });
71326
+ const sdtBoundaries = sdtContainerKeys.map((key2, index2) => {
71327
+ if (!key2) return void 0;
71328
+ const prev = index2 > 0 ? sdtContainerKeys[index2 - 1] : null;
71329
+ const next2 = index2 < sdtContainerKeys.length - 1 ? sdtContainerKeys[index2 + 1] : null;
71330
+ return { isStart: key2 !== prev, isEnd: key2 !== next2 };
71331
+ });
71332
+ const tableSdtKey = tableSdt ? getSdtContainerKey(tableSdt, null) : null;
71333
+ const shouldApplySdtContainerStyling = (sdt, containerSdt, blockKey) => {
71334
+ const resolvedKey = blockKey ?? getSdtContainerKey(sdt, containerSdt);
71335
+ if (tableSdtKey && resolvedKey && tableSdtKey === resolvedKey) {
71336
+ return false;
71337
+ }
71338
+ if (tableSdt && (sdt === tableSdt || containerSdt === tableSdt)) {
71339
+ return false;
71340
+ }
71341
+ return Boolean(getSdtContainerConfig(sdt) || getSdtContainerConfig(containerSdt));
71342
+ };
71343
+ const hasSdtContainer = cellBlocks.some((block, index2) => {
71344
+ const attrs2 = block.attrs;
71345
+ const blockKey = sdtContainerKeys[index2] ?? null;
71346
+ return shouldApplySdtContainerStyling(attrs2?.sdt, attrs2?.containerSdt, blockKey);
71347
+ });
71348
+ if (hasSdtContainer) {
71349
+ cellEl.style.overflow = "visible";
71350
+ }
71157
71351
  if (cellBlocks.length > 0 && blockMeasures.length > 0) {
71158
71352
  const content2 = doc2.createElement("div");
71159
71353
  content2.style.position = "relative";
@@ -71185,6 +71379,26 @@ ${l}
71185
71379
  for (let i2 = 0; i2 < Math.min(blockMeasures.length, cellBlocks.length); i2++) {
71186
71380
  const blockMeasure = blockMeasures[i2];
71187
71381
  const block = cellBlocks[i2];
71382
+ if (blockMeasure.kind === "table" && block?.kind === "table") {
71383
+ const tableMeasure = blockMeasure;
71384
+ const tableWrapper = doc2.createElement("div");
71385
+ tableWrapper.style.position = "relative";
71386
+ tableWrapper.style.width = "100%";
71387
+ tableWrapper.style.height = `${tableMeasure.totalHeight}px`;
71388
+ tableWrapper.style.boxSizing = "border-box";
71389
+ const tableEl = renderEmbeddedTable({
71390
+ doc: doc2,
71391
+ table: block,
71392
+ measure: tableMeasure,
71393
+ context: { ...context, section: "body" },
71394
+ renderLine,
71395
+ renderDrawingContent,
71396
+ applySdtDataset
71397
+ });
71398
+ tableWrapper.appendChild(tableEl);
71399
+ content2.appendChild(tableWrapper);
71400
+ continue;
71401
+ }
71188
71402
  if (blockMeasure.kind === "image" && block?.kind === "image") {
71189
71403
  const imageWrapper = doc2.createElement("div");
71190
71404
  imageWrapper.style.position = "relative";
@@ -71280,6 +71494,11 @@ ${l}
71280
71494
  paraWrapper.style.left = "0";
71281
71495
  paraWrapper.style.width = "100%";
71282
71496
  applySdtDataset(paraWrapper, block.attrs?.sdt);
71497
+ const sdtBoundary = sdtBoundaries[i2];
71498
+ const blockKey = sdtContainerKeys[i2] ?? null;
71499
+ if (shouldApplySdtContainerStyling(block.attrs?.sdt, block.attrs?.containerSdt, blockKey)) {
71500
+ applySdtContainerStyling(doc2, paraWrapper, block.attrs?.sdt, block.attrs?.containerSdt, sdtBoundary);
71501
+ }
71283
71502
  applyParagraphBordersAndShading(paraWrapper, block);
71284
71503
  applyParagraphBorderStyles(paraWrapper, block.attrs?.borders);
71285
71504
  applyParagraphShadingStyles(paraWrapper, block.attrs?.shading);
@@ -71354,8 +71573,6 @@ ${l}
71354
71573
  }
71355
71574
  }
71356
71575
  cumulativeLineCount += blockLineCount;
71357
- } else {
71358
- cumulativeLineCount += 0;
71359
71576
  }
71360
71577
  }
71361
71578
  }
@@ -71377,6 +71594,7 @@ ${l}
71377
71594
  renderLine,
71378
71595
  renderDrawingContent,
71379
71596
  applySdtDataset,
71597
+ tableSdt,
71380
71598
  continuesFromPrev,
71381
71599
  continuesOnNext,
71382
71600
  partialRow
@@ -71471,60 +71689,18 @@ ${l}
71471
71689
  cellMeasure,
71472
71690
  cell: cell2,
71473
71691
  borders: resolvedBorders,
71692
+ useDefaultBorder: false,
71474
71693
  renderLine,
71475
71694
  renderDrawingContent,
71476
71695
  context,
71477
71696
  applySdtDataset,
71697
+ tableSdt,
71478
71698
  fromLine,
71479
71699
  toLine
71480
71700
  });
71481
71701
  container.appendChild(cellElement);
71482
71702
  }
71483
71703
  };
71484
- function isStructuredContentMetadata(sdt) {
71485
- return sdt !== null && sdt !== void 0 && typeof sdt === "object" && "type" in sdt && sdt.type === "structuredContent";
71486
- }
71487
- function isDocumentSectionMetadata(sdt) {
71488
- return sdt !== null && sdt !== void 0 && typeof sdt === "object" && "type" in sdt && sdt.type === "documentSection";
71489
- }
71490
- function getSdtContainerConfig(sdt) {
71491
- if (isDocumentSectionMetadata(sdt)) {
71492
- return {
71493
- className: "superdoc-document-section",
71494
- labelText: sdt.title ?? "Document section",
71495
- labelClassName: "superdoc-document-section__tooltip",
71496
- isStart: true,
71497
- isEnd: true
71498
- };
71499
- }
71500
- if (isStructuredContentMetadata(sdt) && sdt.scope === "block") {
71501
- return {
71502
- className: "superdoc-structured-content-block",
71503
- labelText: sdt.alias ?? "Structured content",
71504
- labelClassName: "superdoc-structured-content__label",
71505
- isStart: true,
71506
- isEnd: true
71507
- };
71508
- }
71509
- return null;
71510
- }
71511
- function applySdtContainerStyling(doc2, container, sdt, containerSdt) {
71512
- let config2 = getSdtContainerConfig(sdt);
71513
- if (!config2 && containerSdt) {
71514
- config2 = getSdtContainerConfig(containerSdt);
71515
- }
71516
- if (!config2) return;
71517
- container.classList.add(config2.className);
71518
- container.dataset.sdtContainerStart = String(config2.isStart);
71519
- container.dataset.sdtContainerEnd = String(config2.isEnd);
71520
- container.style.overflow = "visible";
71521
- const labelEl = doc2.createElement("div");
71522
- labelEl.className = config2.labelClassName;
71523
- const labelText = doc2.createElement("span");
71524
- labelText.textContent = config2.labelText;
71525
- labelEl.appendChild(labelText);
71526
- container.appendChild(labelEl);
71527
- }
71528
71704
  const renderTableFragment = (deps) => {
71529
71705
  const {
71530
71706
  doc: doc2,
@@ -71668,6 +71844,7 @@ ${l}
71668
71844
  renderLine,
71669
71845
  renderDrawingContent,
71670
71846
  applySdtDataset,
71847
+ tableSdt: block.attrs?.sdt ?? null,
71671
71848
  // Headers are always rendered as-is (no border suppression)
71672
71849
  continuesFromPrev: false,
71673
71850
  continuesOnNext: false
@@ -71698,6 +71875,7 @@ ${l}
71698
71875
  renderLine,
71699
71876
  renderDrawingContent,
71700
71877
  applySdtDataset,
71878
+ tableSdt: block.attrs?.sdt ?? null,
71701
71879
  // Draw top border if table continues from previous fragment (MS Word behavior)
71702
71880
  continuesFromPrev: isFirstRenderedBodyRow && fragment.continuesFromPrev === true,
71703
71881
  // Draw bottom border if table continues on next fragment (MS Word behavior)
@@ -72950,8 +73128,10 @@ ${l}
72950
73128
  section: "body",
72951
73129
  pageNumberText: page.numberText
72952
73130
  };
72953
- page.fragments.forEach((fragment) => {
72954
- el.appendChild(this.renderFragment(fragment, contextBase));
73131
+ const sdtBoundaries = computeSdtBoundaries(page.fragments, this.blockLookup);
73132
+ page.fragments.forEach((fragment, index2) => {
73133
+ const sdtBoundary = sdtBoundaries.get(index2);
73134
+ el.appendChild(this.renderFragment(fragment, contextBase, sdtBoundary));
72955
73135
  });
72956
73136
  this.renderDecorationsForPage(el, page);
72957
73137
  return el;
@@ -73182,6 +73362,7 @@ ${l}
73182
73362
  pageEl.dataset.layoutEpoch = String(this.layoutEpoch);
73183
73363
  const existing = new Map(state.fragments.map((frag) => [frag.key, frag]));
73184
73364
  const nextFragments = [];
73365
+ const sdtBoundaries = computeSdtBoundaries(page.fragments, this.blockLookup);
73185
73366
  const contextBase = {
73186
73367
  pageNumber: page.number,
73187
73368
  totalPages: this.totalPages,
@@ -73191,11 +73372,13 @@ ${l}
73191
73372
  page.fragments.forEach((fragment, index2) => {
73192
73373
  const key2 = fragmentKey(fragment);
73193
73374
  const current = existing.get(key2);
73375
+ const sdtBoundary = sdtBoundaries.get(index2);
73194
73376
  if (current) {
73195
73377
  existing.delete(key2);
73196
- const needsRebuild = this.changedBlocks.has(fragment.blockId) || current.signature !== fragmentSignature(fragment, this.blockLookup);
73378
+ const sdtBoundaryMismatch = shouldRebuildForSdtBoundary(current.element, sdtBoundary);
73379
+ const needsRebuild = this.changedBlocks.has(fragment.blockId) || current.signature !== fragmentSignature(fragment, this.blockLookup) || sdtBoundaryMismatch;
73197
73380
  if (needsRebuild) {
73198
- const replacement = this.renderFragment(fragment, contextBase);
73381
+ const replacement = this.renderFragment(fragment, contextBase, sdtBoundary);
73199
73382
  pageEl.replaceChild(replacement, current.element);
73200
73383
  current.element = replacement;
73201
73384
  current.signature = fragmentSignature(fragment, this.blockLookup);
@@ -73209,7 +73392,7 @@ ${l}
73209
73392
  nextFragments.push(current);
73210
73393
  return;
73211
73394
  }
73212
- const fresh = this.renderFragment(fragment, contextBase);
73395
+ const fresh = this.renderFragment(fragment, contextBase, sdtBoundary);
73213
73396
  pageEl.insertBefore(fresh, pageEl.children[index2] ?? null);
73214
73397
  nextFragments.push({
73215
73398
  key: key2,
@@ -73281,8 +73464,10 @@ ${l}
73281
73464
  totalPages: this.totalPages,
73282
73465
  section: "body"
73283
73466
  };
73284
- const fragments = page.fragments.map((fragment) => {
73285
- const fragmentEl = this.renderFragment(fragment, contextBase);
73467
+ const sdtBoundaries = computeSdtBoundaries(page.fragments, this.blockLookup);
73468
+ const fragments = page.fragments.map((fragment, index2) => {
73469
+ const sdtBoundary = sdtBoundaries.get(index2);
73470
+ const fragmentEl = this.renderFragment(fragment, contextBase, sdtBoundary);
73286
73471
  el.appendChild(fragmentEl);
73287
73472
  return {
73288
73473
  key: fragmentKey(fragment),
@@ -73302,12 +73487,12 @@ ${l}
73302
73487
  }
73303
73488
  return this.options.pageStyles;
73304
73489
  }
73305
- renderFragment(fragment, context) {
73490
+ renderFragment(fragment, context, sdtBoundary) {
73306
73491
  if (fragment.kind === "para") {
73307
- return this.renderParagraphFragment(fragment, context);
73492
+ return this.renderParagraphFragment(fragment, context, sdtBoundary);
73308
73493
  }
73309
73494
  if (fragment.kind === "list-item") {
73310
- return this.renderListItemFragment(fragment, context);
73495
+ return this.renderListItemFragment(fragment, context, sdtBoundary);
73311
73496
  }
73312
73497
  if (fragment.kind === "image") {
73313
73498
  return this.renderImageFragment(fragment, context);
@@ -73326,9 +73511,10 @@ ${l}
73326
73511
  *
73327
73512
  * @param fragment - The paragraph fragment to render
73328
73513
  * @param context - Rendering context with page and column information
73514
+ * @param sdtBoundary - Optional SDT boundary overrides for multi-fragment containers
73329
73515
  * @returns HTMLElement containing the rendered fragment or error placeholder
73330
73516
  */
73331
- renderParagraphFragment(fragment, context) {
73517
+ renderParagraphFragment(fragment, context, sdtBoundary) {
73332
73518
  try {
73333
73519
  const lookup = this.blockLookup.get(fragment.blockId);
73334
73520
  if (!lookup || lookup.block.kind !== "paragraph" || lookup.measure.kind !== "paragraph") {
@@ -73375,7 +73561,7 @@ ${l}
73375
73561
  }
73376
73562
  this.applySdtDataset(fragmentEl, block.attrs?.sdt);
73377
73563
  this.applyContainerSdtDataset(fragmentEl, block.attrs?.containerSdt);
73378
- applySdtContainerStyling(this.doc, fragmentEl, block.attrs?.sdt, block.attrs?.containerSdt);
73564
+ applySdtContainerStyling(this.doc, fragmentEl, block.attrs?.sdt, block.attrs?.containerSdt, sdtBoundary);
73379
73565
  const dropCapDescriptor = block.attrs?.dropCapDescriptor;
73380
73566
  const dropCapMeasure = measure.dropCap;
73381
73567
  if (dropCapDescriptor && dropCapMeasure && !fragment.continuesFromPrev) {
@@ -73689,7 +73875,7 @@ ${l}
73689
73875
  }
73690
73876
  return dropCapEl;
73691
73877
  }
73692
- renderListItemFragment(fragment, context) {
73878
+ renderListItemFragment(fragment, context, sdtBoundary) {
73693
73879
  try {
73694
73880
  const lookup = this.blockLookup.get(fragment.blockId);
73695
73881
  if (!lookup || lookup.block.kind !== "list" || lookup.measure.kind !== "list") {
@@ -73715,7 +73901,13 @@ ${l}
73715
73901
  fragmentEl.dataset.itemId = fragment.itemId;
73716
73902
  const paragraphMetadata = item.paragraph.attrs?.sdt;
73717
73903
  this.applySdtDataset(fragmentEl, paragraphMetadata);
73718
- applySdtContainerStyling(this.doc, fragmentEl, paragraphMetadata, item.paragraph.attrs?.containerSdt);
73904
+ applySdtContainerStyling(
73905
+ this.doc,
73906
+ fragmentEl,
73907
+ paragraphMetadata,
73908
+ item.paragraph.attrs?.containerSdt,
73909
+ sdtBoundary
73910
+ );
73719
73911
  if (fragment.continuesFromPrev) {
73720
73912
  fragmentEl.dataset.continuesFromPrev = "true";
73721
73913
  }
@@ -75645,6 +75837,46 @@ ${l}
75645
75837
  }
75646
75838
  }
75647
75839
  }
75840
+ const getFragmentSdtContainerKey = (fragment, blockLookup) => {
75841
+ const lookup = blockLookup.get(fragment.blockId);
75842
+ if (!lookup) return null;
75843
+ const block = lookup.block;
75844
+ if (fragment.kind === "para" && block.kind === "paragraph") {
75845
+ const attrs = block.attrs;
75846
+ return getSdtContainerKey(attrs?.sdt, attrs?.containerSdt);
75847
+ }
75848
+ if (fragment.kind === "list-item" && block.kind === "list") {
75849
+ const item = block.items.find((listItem2) => listItem2.id === fragment.itemId);
75850
+ const attrs = item?.paragraph.attrs;
75851
+ return getSdtContainerKey(attrs?.sdt, attrs?.containerSdt);
75852
+ }
75853
+ return null;
75854
+ };
75855
+ const computeSdtBoundaries = (fragments, blockLookup) => {
75856
+ const boundaries = /* @__PURE__ */ new Map();
75857
+ const containerKeys = fragments.map((fragment) => getFragmentSdtContainerKey(fragment, blockLookup));
75858
+ for (let i2 = 0; i2 < fragments.length; i2 += 1) {
75859
+ const currentKey = containerKeys[i2];
75860
+ if (!currentKey) continue;
75861
+ const prev = i2 > 0 ? containerKeys[i2 - 1] : null;
75862
+ const next2 = i2 < fragments.length - 1 ? containerKeys[i2 + 1] : null;
75863
+ const isStart = currentKey !== prev;
75864
+ const isEnd = currentKey !== next2;
75865
+ boundaries.set(i2, { isStart, isEnd });
75866
+ }
75867
+ return boundaries;
75868
+ };
75869
+ const shouldRebuildForSdtBoundary = (element2, boundary) => {
75870
+ if (!boundary) return false;
75871
+ const startAttr = element2.dataset.sdtContainerStart;
75872
+ const endAttr = element2.dataset.sdtContainerEnd;
75873
+ const expectedStart = String(boundary.isStart ?? true);
75874
+ const expectedEnd = String(boundary.isEnd ?? true);
75875
+ if (startAttr === void 0 || endAttr === void 0) {
75876
+ return true;
75877
+ }
75878
+ return startAttr !== expectedStart || endAttr !== expectedEnd;
75879
+ };
75648
75880
  const fragmentKey = (fragment) => {
75649
75881
  if (fragment.kind === "para") {
75650
75882
  return `para:${fragment.blockId}:${fragment.fromLine}:${fragment.toLine}`;
@@ -81313,8 +81545,15 @@ ${l}
81313
81545
  const paraBlock = block;
81314
81546
  const isEmpty2 = !paraBlock.runs || paraBlock.runs.length === 0 || paraBlock.runs.length === 1 && (!paraBlock.runs[0].kind || paraBlock.runs[0].kind === "text") && (!paraBlock.runs[0].text || paraBlock.runs[0].text === "");
81315
81547
  if (isEmpty2) {
81548
+ const isSectPrMarker = paraBlock.attrs?.sectPrMarker === true;
81316
81549
  const prevBlock = index2 > 0 ? blocks2[index2 - 1] : null;
81317
81550
  const nextBlock = index2 < blocks2.length - 1 ? blocks2[index2 + 1] : null;
81551
+ const nextSectionBreak = nextBlock?.kind === "sectionBreak" ? nextBlock : null;
81552
+ const nextBreakType = nextSectionBreak?.type ?? (nextSectionBreak?.attrs?.source === "sectPr" ? "nextPage" : void 0);
81553
+ const nextBreakForcesPage = nextSectionBreak && (nextBreakType === "nextPage" || nextBreakType === "evenPage" || nextBreakType === "oddPage" || nextSectionBreak.attrs?.requirePageBoundary === true);
81554
+ if (isSectPrMarker && nextBreakForcesPage) {
81555
+ continue;
81556
+ }
81318
81557
  if (prevBlock?.kind === "pageBreak" && nextBlock?.kind === "sectionBreak") {
81319
81558
  continue;
81320
81559
  }
@@ -88995,16 +89234,6 @@ ${l}
88995
89234
  if (marksAsAttrs.length > 0) {
88996
89235
  run2._explicitFont = true;
88997
89236
  }
88998
- console.debug("[token-debug] tokenNodeToRun", {
88999
- token,
89000
- fontFamily: run2.fontFamily,
89001
- fontSize: run2.fontSize,
89002
- defaultFont,
89003
- defaultSize,
89004
- nodeMarksCount: nodeMarks.length,
89005
- marksAsAttrsCount: marksAsAttrs.length,
89006
- inheritedMarksCount: inheritedMarks?.length ?? 0
89007
- });
89008
89237
  return run2;
89009
89238
  }
89010
89239
  const EIGHTHS_PER_POINT = 8;
@@ -91400,6 +91629,16 @@ ${l}
91400
91629
  table2.attrs.sdt = metadata;
91401
91630
  table2.rows?.forEach((row2) => {
91402
91631
  row2.cells?.forEach((cell2) => {
91632
+ const cellBlocks = cell2.blocks;
91633
+ if (cellBlocks && cellBlocks.length > 0) {
91634
+ applySdtMetadataToParagraphBlocks(cellBlocks, metadata);
91635
+ cellBlocks.forEach((block) => {
91636
+ if (block.kind === "table") {
91637
+ applySdtMetadataToTableBlock(block, metadata);
91638
+ }
91639
+ });
91640
+ return;
91641
+ }
91403
91642
  if (cell2.paragraph) {
91404
91643
  applySdtMetadataToParagraphBlocks([cell2.paragraph], metadata);
91405
91644
  }
@@ -92623,6 +92862,10 @@ ${l}
92623
92862
  }
92624
92863
  const linkedStyleResolver = createLinkedStyleResolver(converterContext?.linkedStyles);
92625
92864
  const blocks2 = [];
92865
+ const paraAttrs = para.attrs ?? {};
92866
+ const rawParagraphProps = typeof paraAttrs.paragraphProperties === "object" && paraAttrs.paragraphProperties !== null ? paraAttrs.paragraphProperties : void 0;
92867
+ const hasSectPr2 = Boolean(rawParagraphProps?.sectPr);
92868
+ const isSectPrMarker = hasSectPr2 || paraAttrs.pageBreakSource === "sectPr";
92626
92869
  if (hasPageBreakBefore(para)) {
92627
92870
  blocks2.push({
92628
92871
  kind: "pageBreak",
@@ -92644,11 +92887,19 @@ ${l}
92644
92887
  emptyRun.pmStart = paraPos.start + 1;
92645
92888
  emptyRun.pmEnd = paraPos.start + 1;
92646
92889
  }
92890
+ let emptyParagraphAttrs = cloneParagraphAttrs(paragraphAttrs);
92891
+ if (isSectPrMarker) {
92892
+ if (emptyParagraphAttrs) {
92893
+ emptyParagraphAttrs.sectPrMarker = true;
92894
+ } else {
92895
+ emptyParagraphAttrs = { sectPrMarker: true };
92896
+ }
92897
+ }
92647
92898
  blocks2.push({
92648
92899
  kind: "paragraph",
92649
92900
  id: baseBlockId,
92650
92901
  runs: [emptyRun],
92651
- attrs: cloneParagraphAttrs(paragraphAttrs)
92902
+ attrs: emptyParagraphAttrs
92652
92903
  });
92653
92904
  return blocks2;
92654
92905
  }
@@ -92902,14 +93153,6 @@ ${l}
92902
93153
  enableComments
92903
93154
  );
92904
93155
  }
92905
- console.debug("[token-debug] paragraph-token-run", {
92906
- token: tokenRun.token,
92907
- fontFamily: tokenRun.fontFamily,
92908
- fontSize: tokenRun.fontSize,
92909
- inlineStyleId,
92910
- runStyleId: activeRunStyleId,
92911
- mergedMarksCount: mergedMarks.length
92912
- });
92913
93156
  applyInlineRunProperties(tokenRun, activeRunProperties);
92914
93157
  currentRuns.push(tokenRun);
92915
93158
  }
@@ -93565,7 +93808,19 @@ ${l}
93565
93808
  ...cellBackgroundColor && { backgroundColor: cellBackgroundColor }
93566
93809
  } : context.converterContext;
93567
93810
  const paragraphToFlowBlocks2 = context.converters?.paragraphToFlowBlocks ?? context.paragraphToFlowBlocks;
93811
+ const tableNodeToBlock2 = context.converters?.tableNodeToBlock;
93568
93812
  const listCounterContext = context.listCounterContext;
93813
+ const appendParagraphBlocks = (paragraphBlocks, sdtMetadata) => {
93814
+ applySdtMetadataToParagraphBlocks(
93815
+ paragraphBlocks.filter((block) => block.kind === "paragraph"),
93816
+ sdtMetadata
93817
+ );
93818
+ paragraphBlocks.forEach((block) => {
93819
+ if (block.kind === "paragraph" || block.kind === "image" || block.kind === "drawing") {
93820
+ blocks2.push(block);
93821
+ }
93822
+ });
93823
+ };
93569
93824
  for (const childNode of cellNode.content) {
93570
93825
  if (childNode.type === "paragraph") {
93571
93826
  if (!paragraphToFlowBlocks2) continue;
@@ -93583,11 +93838,75 @@ ${l}
93583
93838
  context.themeColors,
93584
93839
  cellConverterContext
93585
93840
  );
93586
- paragraphBlocks.forEach((block) => {
93587
- if (block.kind === "paragraph" || block.kind === "image" || block.kind === "drawing") {
93588
- blocks2.push(block);
93841
+ appendParagraphBlocks(paragraphBlocks);
93842
+ continue;
93843
+ }
93844
+ if (childNode.type === "structuredContentBlock" && Array.isArray(childNode.content)) {
93845
+ const structuredContentMetadata = resolveNodeSdtMetadata(childNode, "structuredContentBlock");
93846
+ for (const nestedNode of childNode.content) {
93847
+ if (nestedNode.type === "paragraph") {
93848
+ if (!paragraphToFlowBlocks2) continue;
93849
+ const paragraphBlocks = paragraphToFlowBlocks2(
93850
+ nestedNode,
93851
+ context.nextBlockId,
93852
+ context.positions,
93853
+ context.defaultFont,
93854
+ context.defaultSize,
93855
+ context.styleContext,
93856
+ listCounterContext,
93857
+ context.trackedChanges,
93858
+ context.bookmarks,
93859
+ context.hyperlinkConfig,
93860
+ context.themeColors,
93861
+ cellConverterContext
93862
+ );
93863
+ appendParagraphBlocks(paragraphBlocks, structuredContentMetadata);
93864
+ continue;
93589
93865
  }
93590
- });
93866
+ if (nestedNode.type === "table" && tableNodeToBlock2) {
93867
+ const tableBlock = tableNodeToBlock2(
93868
+ nestedNode,
93869
+ context.nextBlockId,
93870
+ context.positions,
93871
+ context.defaultFont,
93872
+ context.defaultSize,
93873
+ context.styleContext,
93874
+ context.trackedChanges,
93875
+ context.bookmarks,
93876
+ context.hyperlinkConfig,
93877
+ context.themeColors,
93878
+ paragraphToFlowBlocks2,
93879
+ context.converterContext,
93880
+ { listCounterContext, converters: context.converters }
93881
+ );
93882
+ if (tableBlock && tableBlock.kind === "table") {
93883
+ applySdtMetadataToTableBlock(tableBlock, structuredContentMetadata);
93884
+ blocks2.push(tableBlock);
93885
+ }
93886
+ continue;
93887
+ }
93888
+ }
93889
+ continue;
93890
+ }
93891
+ if (childNode.type === "table" && tableNodeToBlock2) {
93892
+ const tableBlock = tableNodeToBlock2(
93893
+ childNode,
93894
+ context.nextBlockId,
93895
+ context.positions,
93896
+ context.defaultFont,
93897
+ context.defaultSize,
93898
+ context.styleContext,
93899
+ context.trackedChanges,
93900
+ context.bookmarks,
93901
+ context.hyperlinkConfig,
93902
+ context.themeColors,
93903
+ paragraphToFlowBlocks2,
93904
+ context.converterContext,
93905
+ { listCounterContext, converters: context.converters }
93906
+ );
93907
+ if (tableBlock && tableBlock.kind === "table") {
93908
+ blocks2.push(tableBlock);
93909
+ }
93591
93910
  continue;
93592
93911
  }
93593
93912
  if (childNode.type === "image" && context.converters?.imageNodeToBlock) {
@@ -93651,6 +93970,7 @@ ${l}
93651
93970
  if (drawingBlock && drawingBlock.kind === "drawing") {
93652
93971
  blocks2.push(drawingBlock);
93653
93972
  }
93973
+ continue;
93654
93974
  }
93655
93975
  }
93656
93976
  if (blocks2.length === 0) {
@@ -99191,6 +99511,39 @@ ${l}
99191
99511
  height: rect.height
99192
99512
  };
99193
99513
  }
99514
+ /**
99515
+ * Get the painted DOM element that contains a document position (body only).
99516
+ *
99517
+ * Uses the DomPositionIndex which maps data-pm-start/end attributes to rendered
99518
+ * elements. Returns null when the position is not currently mounted (virtualization)
99519
+ * or when in header/footer mode.
99520
+ *
99521
+ * @param pos - Document position in the active editor
99522
+ * @param options.forceRebuild - Rebuild the index before lookup
99523
+ * @param options.fallbackToCoords - Use elementFromPoint with layout rects if index lookup fails
99524
+ * @returns The nearest painted DOM element for the position, or null if unavailable
99525
+ */
99526
+ getElementAtPos(pos, options = {}) {
99527
+ if (!Number.isFinite(pos)) return null;
99528
+ if (!this.#painterHost) return null;
99529
+ if (this.#session.mode !== "body") return null;
99530
+ if (options.forceRebuild || this.#domPositionIndex.size === 0) {
99531
+ this.#rebuildDomPositionIndex();
99532
+ }
99533
+ const indexed = this.#domPositionIndex.findElementAtPosition(pos);
99534
+ if (indexed) return indexed;
99535
+ if (!options.fallbackToCoords) return null;
99536
+ const rects = this.getRangeRects(pos, pos);
99537
+ if (!rects.length) return null;
99538
+ const doc2 = this.#visibleHost.ownerDocument ?? document;
99539
+ for (const rect of rects) {
99540
+ const el = doc2.elementFromPoint(rect.left + rect.width / 2, rect.top + rect.height / 2);
99541
+ if (el instanceof HTMLElement && this.#painterHost.contains(el)) {
99542
+ return el.closest("[data-pm-start][data-pm-end]") ?? el;
99543
+ }
99544
+ }
99545
+ return null;
99546
+ }
99194
99547
  /**
99195
99548
  * Scroll the visible host so a given document position is brought into view.
99196
99549
  *
@@ -145585,7 +145938,7 @@ ${reason}`);
145585
145938
  this.config.colors = shuffleArray(this.config.colors);
145586
145939
  this.userColorMap = /* @__PURE__ */ new Map();
145587
145940
  this.colorIndex = 0;
145588
- this.version = "1.4.1-next.2";
145941
+ this.version = "1.5.0-next.1";
145589
145942
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
145590
145943
  this.superdocId = config2.superdocId || v4();
145591
145944
  this.colors = this.config.colors;