@harbour-enterprises/superdoc 1.4.1-next.3 → 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.
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  const jszip = require("./jszip-C8_CqJxM.cjs");
3
3
  const helpers$1 = require("./helpers-nOdwpmwb.cjs");
4
- const superEditor_converter = require("./SuperConverter-D8OyLf2e.cjs");
4
+ const superEditor_converter = require("./SuperConverter-BVAV03p6.cjs");
5
5
  const vue = require("./vue-De9wkgLl.cjs");
6
6
  require("./jszip.min-BPh2MMAa.cjs");
7
7
  const eventemitter3 = require("./eventemitter3-BQuRcMPI.cjs");
@@ -15516,7 +15516,7 @@ const canUseDOM = () => {
15516
15516
  return false;
15517
15517
  }
15518
15518
  };
15519
- const summaryVersion = "1.4.1-next.3";
15519
+ const summaryVersion = "1.5.0-next.1";
15520
15520
  const nodeKeys = ["group", "content", "marks", "inline", "atom", "defining", "code", "tableRole", "summary"];
15521
15521
  const markKeys = ["group", "inclusive", "excludes", "spanning", "code"];
15522
15522
  function mapAttributes(attrs) {
@@ -16826,6 +16826,31 @@ class Editor extends EventEmitter {
16826
16826
  }
16827
16827
  return null;
16828
16828
  }
16829
+ /**
16830
+ * Get the DOM element for a document position.
16831
+ * In presentation mode, returns the painted element.
16832
+ */
16833
+ getElementAtPos(pos, options = {}) {
16834
+ if (this.presentationEditor) {
16835
+ return this.presentationEditor.getElementAtPos(pos, options);
16836
+ }
16837
+ if (!this.view) return null;
16838
+ if (!Number.isFinite(pos)) return null;
16839
+ const maxPos = this.view.state.doc.content.size;
16840
+ const clampedPos = Math.max(0, Math.min(pos, maxPos));
16841
+ try {
16842
+ const { node } = this.view.domAtPos(clampedPos);
16843
+ if (node && node.nodeType === 1) {
16844
+ return node;
16845
+ }
16846
+ if (node && node.nodeType === 3) {
16847
+ return node.parentElement;
16848
+ }
16849
+ return node?.parentElement ?? null;
16850
+ } catch {
16851
+ return null;
16852
+ }
16853
+ }
16829
16854
  /**
16830
16855
  * Get position from client-space coordinates.
16831
16856
  * In layout/presentation mode, uses PresentationEditor hit testing for accurate coordinate mapping.
@@ -18148,7 +18173,7 @@ class Editor extends EventEmitter {
18148
18173
  * Process collaboration migrations
18149
18174
  */
18150
18175
  processCollaborationMigrations() {
18151
- console.debug("[checkVersionMigrations] Current editor version", "1.4.1-next.3");
18176
+ console.debug("[checkVersionMigrations] Current editor version", "1.5.0-next.1");
18152
18177
  if (!this.options.ydoc) return;
18153
18178
  const metaMap = this.options.ydoc.getMap("meta");
18154
18179
  let docVersion = metaMap.get("version");
@@ -23172,27 +23197,33 @@ const SDT_CONTAINER_STYLES = `
23172
23197
  align-items: center;
23173
23198
  }
23174
23199
 
23175
- /* Continuation styling: first fragment has top corners, last has bottom corners */
23176
- .superdoc-document-section[data-sdt-container-start="true"] {
23177
- border-radius: 4px 4px 0 0;
23200
+ /* Continuation styling: SDT container boundary handling for multi-fragment document sections */
23201
+ /* Single fragment (both start and end): full border radius */
23202
+ .superdoc-document-section[data-sdt-container-start="true"][data-sdt-container-end="true"] {
23203
+ border-radius: 4px;
23178
23204
  }
23179
23205
 
23180
- .superdoc-document-section[data-sdt-container-end="true"] {
23181
- border-radius: 0 0 4px 4px;
23206
+ /* First fragment of a multi-fragment SDT: top corners, no bottom border */
23207
+ .superdoc-document-section[data-sdt-container-start="true"]:not([data-sdt-container-end="true"]) {
23208
+ border-radius: 4px 4px 0 0;
23209
+ border-bottom: none;
23182
23210
  }
23183
23211
 
23184
- .superdoc-document-section[data-sdt-container-start="true"][data-sdt-container-end="true"] {
23185
- border-radius: 4px;
23212
+ /* Last fragment of a multi-fragment SDT: bottom corners, no top border */
23213
+ .superdoc-document-section[data-sdt-container-end="true"]:not([data-sdt-container-start="true"]) {
23214
+ border-radius: 0 0 4px 4px;
23215
+ border-top: none;
23186
23216
  }
23187
23217
 
23188
23218
  .superdoc-document-section[data-sdt-container-start="true"]:hover {
23189
23219
  border-radius: 0 4px 0 0;
23190
23220
  }
23191
23221
 
23192
- /* Middle fragments have no border radius */
23222
+ /* Middle fragments (neither start nor end): no corners, no top/bottom borders */
23193
23223
  .superdoc-document-section:not([data-sdt-container-start="true"]):not([data-sdt-container-end="true"]) {
23194
23224
  border-radius: 0;
23195
23225
  border-top: none;
23226
+ border-bottom: none;
23196
23227
  }
23197
23228
 
23198
23229
  /* Structured Content Block - Blue border container */
@@ -23239,21 +23270,28 @@ const SDT_CONTAINER_STYLES = `
23239
23270
  }
23240
23271
 
23241
23272
  /* Continuation styling for structured content blocks */
23242
- .superdoc-structured-content-block[data-sdt-container-start="true"] {
23243
- border-radius: 4px 4px 0 0;
23273
+ /* Single fragment (both start and end): full border radius */
23274
+ .superdoc-structured-content-block[data-sdt-container-start="true"][data-sdt-container-end="true"] {
23275
+ border-radius: 4px;
23244
23276
  }
23245
23277
 
23246
- .superdoc-structured-content-block[data-sdt-container-end="true"] {
23247
- border-radius: 0 0 4px 4px;
23278
+ /* First fragment of a multi-fragment SDT: top corners, no bottom border */
23279
+ .superdoc-structured-content-block[data-sdt-container-start="true"]:not([data-sdt-container-end="true"]) {
23280
+ border-radius: 4px 4px 0 0;
23281
+ border-bottom: none;
23248
23282
  }
23249
23283
 
23250
- .superdoc-structured-content-block[data-sdt-container-start="true"][data-sdt-container-end="true"] {
23251
- border-radius: 4px;
23284
+ /* Last fragment of a multi-fragment SDT: bottom corners, no top border */
23285
+ .superdoc-structured-content-block[data-sdt-container-end="true"]:not([data-sdt-container-start="true"]) {
23286
+ border-radius: 0 0 4px 4px;
23287
+ border-top: none;
23252
23288
  }
23253
23289
 
23290
+ /* Middle fragment (neither start nor end): no corners, no top/bottom borders */
23254
23291
  .superdoc-structured-content-block:not([data-sdt-container-start="true"]):not([data-sdt-container-end="true"]) {
23255
23292
  border-radius: 0;
23256
23293
  border-top: none;
23294
+ border-bottom: none;
23257
23295
  }
23258
23296
 
23259
23297
  /* Structured Content Inline - Inline wrapper with blue border */
@@ -23722,6 +23760,78 @@ const resolveTableCellBorders = (tableBorders, rowIndex, colIndex, totalRows, to
23722
23760
  right: borderValueToSpec(isLastCol ? tableBorders?.right : null)
23723
23761
  };
23724
23762
  };
23763
+ function isStructuredContentMetadata(sdt) {
23764
+ return sdt !== null && sdt !== void 0 && typeof sdt === "object" && "type" in sdt && sdt.type === "structuredContent";
23765
+ }
23766
+ function isDocumentSectionMetadata(sdt) {
23767
+ return sdt !== null && sdt !== void 0 && typeof sdt === "object" && "type" in sdt && sdt.type === "documentSection";
23768
+ }
23769
+ function getSdtContainerConfig(sdt) {
23770
+ if (isDocumentSectionMetadata(sdt)) {
23771
+ return {
23772
+ className: "superdoc-document-section",
23773
+ labelText: sdt.title ?? "Document section",
23774
+ labelClassName: "superdoc-document-section__tooltip",
23775
+ isStart: true,
23776
+ isEnd: true
23777
+ };
23778
+ }
23779
+ if (isStructuredContentMetadata(sdt) && sdt.scope === "block") {
23780
+ return {
23781
+ className: "superdoc-structured-content-block",
23782
+ labelText: sdt.alias ?? "Structured content",
23783
+ labelClassName: "superdoc-structured-content__label",
23784
+ isStart: true,
23785
+ isEnd: true
23786
+ };
23787
+ }
23788
+ return null;
23789
+ }
23790
+ function getSdtContainerMetadata(sdt, containerSdt) {
23791
+ if (getSdtContainerConfig(sdt)) return sdt ?? null;
23792
+ if (getSdtContainerConfig(containerSdt)) return containerSdt ?? null;
23793
+ return null;
23794
+ }
23795
+ function getSdtContainerKey(sdt, containerSdt) {
23796
+ const metadata = getSdtContainerMetadata(sdt, containerSdt);
23797
+ if (!metadata) return null;
23798
+ if (metadata.type === "structuredContent") {
23799
+ if (metadata.scope !== "block") return null;
23800
+ if (!metadata.id) {
23801
+ return null;
23802
+ }
23803
+ return `structuredContent:${metadata.id}`;
23804
+ }
23805
+ if (metadata.type === "documentSection") {
23806
+ const sectionId = metadata.id ?? metadata.sdBlockId;
23807
+ if (!sectionId) {
23808
+ return null;
23809
+ }
23810
+ return `documentSection:${sectionId}`;
23811
+ }
23812
+ return null;
23813
+ }
23814
+ function applySdtContainerStyling(doc2, container, sdt, containerSdt, boundaryOptions) {
23815
+ let config = getSdtContainerConfig(sdt);
23816
+ if (!config && containerSdt) {
23817
+ config = getSdtContainerConfig(containerSdt);
23818
+ }
23819
+ if (!config) return;
23820
+ const isStart = boundaryOptions?.isStart ?? config.isStart;
23821
+ const isEnd = boundaryOptions?.isEnd ?? config.isEnd;
23822
+ container.classList.add(config.className);
23823
+ container.dataset.sdtContainerStart = String(isStart);
23824
+ container.dataset.sdtContainerEnd = String(isEnd);
23825
+ container.style.overflow = "visible";
23826
+ if (isStart) {
23827
+ const labelEl = doc2.createElement("div");
23828
+ labelEl.className = config.labelClassName;
23829
+ const labelText = doc2.createElement("span");
23830
+ labelText.textContent = config.labelText;
23831
+ labelEl.appendChild(labelText);
23832
+ container.appendChild(labelEl);
23833
+ }
23834
+ }
23725
23835
  const LIST_MARKER_GAP$3 = 8;
23726
23836
  function renderListMarker(params2) {
23727
23837
  const { doc: doc2, lineEl, markerLayout, markerMeasure, indentLeftPx } = params2;
@@ -23759,6 +23869,54 @@ function renderListMarker(params2) {
23759
23869
  lineContainer.appendChild(lineEl);
23760
23870
  return lineContainer;
23761
23871
  }
23872
+ const applyInlineStyles = (el, styles) => {
23873
+ Object.entries(styles).forEach(([key2, value]) => {
23874
+ if (value != null && value !== "" && key2 in el.style) {
23875
+ el.style[key2] = String(value);
23876
+ }
23877
+ });
23878
+ };
23879
+ const EMBEDDED_TABLE_VERSION = "embedded-table";
23880
+ const renderEmbeddedTable = (params2) => {
23881
+ const { doc: doc2, table, measure, context, renderLine, renderDrawingContent, applySdtDataset } = params2;
23882
+ const fragment = {
23883
+ kind: "table",
23884
+ blockId: table.id,
23885
+ fromRow: 0,
23886
+ toRow: table.rows.length,
23887
+ x: 0,
23888
+ y: 0,
23889
+ width: measure.totalWidth,
23890
+ height: measure.totalHeight
23891
+ };
23892
+ const blockLookup = /* @__PURE__ */ new Map([
23893
+ [
23894
+ table.id,
23895
+ {
23896
+ block: table,
23897
+ measure,
23898
+ version: EMBEDDED_TABLE_VERSION
23899
+ }
23900
+ ]
23901
+ ]);
23902
+ const applyFragmentFrame = (el, frag) => {
23903
+ el.style.left = `${frag.x}px`;
23904
+ el.style.top = `${frag.y}px`;
23905
+ el.style.width = `${frag.width}px`;
23906
+ el.dataset.blockId = frag.blockId;
23907
+ };
23908
+ return renderTableFragment({
23909
+ doc: doc2,
23910
+ fragment,
23911
+ context,
23912
+ blockLookup,
23913
+ renderLine,
23914
+ renderDrawingContent,
23915
+ applyFragmentFrame,
23916
+ applySdtDataset,
23917
+ applyStyles: applyInlineStyles
23918
+ });
23919
+ };
23762
23920
  function applyParagraphBordersAndShading(paraWrapper, block) {
23763
23921
  const borders = block.attrs?.borders;
23764
23922
  if (borders) {
@@ -23799,10 +23957,12 @@ const renderTableCell = (deps) => {
23799
23957
  cellMeasure,
23800
23958
  cell,
23801
23959
  borders,
23960
+ useDefaultBorder,
23802
23961
  renderLine,
23803
23962
  renderDrawingContent,
23804
23963
  context,
23805
23964
  applySdtDataset,
23965
+ tableSdt,
23806
23966
  fromLine,
23807
23967
  toLine
23808
23968
  } = deps;
@@ -23826,12 +23986,46 @@ const renderTableCell = (deps) => {
23826
23986
  cellEl.style.paddingBottom = `${paddingBottom}px`;
23827
23987
  if (borders) {
23828
23988
  applyCellBorders(cellEl, borders);
23989
+ } else if (useDefaultBorder) {
23990
+ cellEl.style.border = "1px solid rgba(0,0,0,0.6)";
23829
23991
  }
23830
23992
  if (cell?.attrs?.background) {
23831
23993
  cellEl.style.backgroundColor = cell.attrs.background;
23832
23994
  }
23833
23995
  const cellBlocks = cell?.blocks ?? (cell?.paragraph ? [cell.paragraph] : []);
23834
23996
  const blockMeasures = cellMeasure?.blocks ?? (cellMeasure?.paragraph ? [cellMeasure.paragraph] : []);
23997
+ const sdtContainerKeys = cellBlocks.map((block) => {
23998
+ if (block.kind !== "paragraph") {
23999
+ return null;
24000
+ }
24001
+ const attrs2 = block.attrs;
24002
+ return getSdtContainerKey(attrs2?.sdt, attrs2?.containerSdt);
24003
+ });
24004
+ const sdtBoundaries = sdtContainerKeys.map((key2, index2) => {
24005
+ if (!key2) return void 0;
24006
+ const prev = index2 > 0 ? sdtContainerKeys[index2 - 1] : null;
24007
+ const next = index2 < sdtContainerKeys.length - 1 ? sdtContainerKeys[index2 + 1] : null;
24008
+ return { isStart: key2 !== prev, isEnd: key2 !== next };
24009
+ });
24010
+ const tableSdtKey = tableSdt ? getSdtContainerKey(tableSdt, null) : null;
24011
+ const shouldApplySdtContainerStyling = (sdt, containerSdt, blockKey) => {
24012
+ const resolvedKey = blockKey ?? getSdtContainerKey(sdt, containerSdt);
24013
+ if (tableSdtKey && resolvedKey && tableSdtKey === resolvedKey) {
24014
+ return false;
24015
+ }
24016
+ if (tableSdt && (sdt === tableSdt || containerSdt === tableSdt)) {
24017
+ return false;
24018
+ }
24019
+ return Boolean(getSdtContainerConfig(sdt) || getSdtContainerConfig(containerSdt));
24020
+ };
24021
+ const hasSdtContainer = cellBlocks.some((block, index2) => {
24022
+ const attrs2 = block.attrs;
24023
+ const blockKey = sdtContainerKeys[index2] ?? null;
24024
+ return shouldApplySdtContainerStyling(attrs2?.sdt, attrs2?.containerSdt, blockKey);
24025
+ });
24026
+ if (hasSdtContainer) {
24027
+ cellEl.style.overflow = "visible";
24028
+ }
23835
24029
  if (cellBlocks.length > 0 && blockMeasures.length > 0) {
23836
24030
  const content = doc2.createElement("div");
23837
24031
  content.style.position = "relative";
@@ -23863,6 +24057,26 @@ const renderTableCell = (deps) => {
23863
24057
  for (let i = 0; i < Math.min(blockMeasures.length, cellBlocks.length); i++) {
23864
24058
  const blockMeasure = blockMeasures[i];
23865
24059
  const block = cellBlocks[i];
24060
+ if (blockMeasure.kind === "table" && block?.kind === "table") {
24061
+ const tableMeasure = blockMeasure;
24062
+ const tableWrapper = doc2.createElement("div");
24063
+ tableWrapper.style.position = "relative";
24064
+ tableWrapper.style.width = "100%";
24065
+ tableWrapper.style.height = `${tableMeasure.totalHeight}px`;
24066
+ tableWrapper.style.boxSizing = "border-box";
24067
+ const tableEl = renderEmbeddedTable({
24068
+ doc: doc2,
24069
+ table: block,
24070
+ measure: tableMeasure,
24071
+ context: { ...context, section: "body" },
24072
+ renderLine,
24073
+ renderDrawingContent,
24074
+ applySdtDataset
24075
+ });
24076
+ tableWrapper.appendChild(tableEl);
24077
+ content.appendChild(tableWrapper);
24078
+ continue;
24079
+ }
23866
24080
  if (blockMeasure.kind === "image" && block?.kind === "image") {
23867
24081
  const imageWrapper = doc2.createElement("div");
23868
24082
  imageWrapper.style.position = "relative";
@@ -23958,6 +24172,11 @@ const renderTableCell = (deps) => {
23958
24172
  paraWrapper.style.left = "0";
23959
24173
  paraWrapper.style.width = "100%";
23960
24174
  applySdtDataset(paraWrapper, block.attrs?.sdt);
24175
+ const sdtBoundary = sdtBoundaries[i];
24176
+ const blockKey = sdtContainerKeys[i] ?? null;
24177
+ if (shouldApplySdtContainerStyling(block.attrs?.sdt, block.attrs?.containerSdt, blockKey)) {
24178
+ applySdtContainerStyling(doc2, paraWrapper, block.attrs?.sdt, block.attrs?.containerSdt, sdtBoundary);
24179
+ }
23961
24180
  applyParagraphBordersAndShading(paraWrapper, block);
23962
24181
  applyParagraphBorderStyles(paraWrapper, block.attrs?.borders);
23963
24182
  applyParagraphShadingStyles(paraWrapper, block.attrs?.shading);
@@ -24032,8 +24251,6 @@ const renderTableCell = (deps) => {
24032
24251
  }
24033
24252
  }
24034
24253
  cumulativeLineCount += blockLineCount;
24035
- } else {
24036
- cumulativeLineCount += 0;
24037
24254
  }
24038
24255
  }
24039
24256
  }
@@ -24055,6 +24272,7 @@ const renderTableRow = (deps) => {
24055
24272
  renderLine,
24056
24273
  renderDrawingContent,
24057
24274
  applySdtDataset,
24275
+ tableSdt,
24058
24276
  continuesFromPrev,
24059
24277
  continuesOnNext,
24060
24278
  partialRow
@@ -24149,60 +24367,18 @@ const renderTableRow = (deps) => {
24149
24367
  cellMeasure,
24150
24368
  cell,
24151
24369
  borders: resolvedBorders,
24370
+ useDefaultBorder: false,
24152
24371
  renderLine,
24153
24372
  renderDrawingContent,
24154
24373
  context,
24155
24374
  applySdtDataset,
24375
+ tableSdt,
24156
24376
  fromLine,
24157
24377
  toLine
24158
24378
  });
24159
24379
  container.appendChild(cellElement);
24160
24380
  }
24161
24381
  };
24162
- function isStructuredContentMetadata(sdt) {
24163
- return sdt !== null && sdt !== void 0 && typeof sdt === "object" && "type" in sdt && sdt.type === "structuredContent";
24164
- }
24165
- function isDocumentSectionMetadata(sdt) {
24166
- return sdt !== null && sdt !== void 0 && typeof sdt === "object" && "type" in sdt && sdt.type === "documentSection";
24167
- }
24168
- function getSdtContainerConfig(sdt) {
24169
- if (isDocumentSectionMetadata(sdt)) {
24170
- return {
24171
- className: "superdoc-document-section",
24172
- labelText: sdt.title ?? "Document section",
24173
- labelClassName: "superdoc-document-section__tooltip",
24174
- isStart: true,
24175
- isEnd: true
24176
- };
24177
- }
24178
- if (isStructuredContentMetadata(sdt) && sdt.scope === "block") {
24179
- return {
24180
- className: "superdoc-structured-content-block",
24181
- labelText: sdt.alias ?? "Structured content",
24182
- labelClassName: "superdoc-structured-content__label",
24183
- isStart: true,
24184
- isEnd: true
24185
- };
24186
- }
24187
- return null;
24188
- }
24189
- function applySdtContainerStyling(doc2, container, sdt, containerSdt) {
24190
- let config = getSdtContainerConfig(sdt);
24191
- if (!config && containerSdt) {
24192
- config = getSdtContainerConfig(containerSdt);
24193
- }
24194
- if (!config) return;
24195
- container.classList.add(config.className);
24196
- container.dataset.sdtContainerStart = String(config.isStart);
24197
- container.dataset.sdtContainerEnd = String(config.isEnd);
24198
- container.style.overflow = "visible";
24199
- const labelEl = doc2.createElement("div");
24200
- labelEl.className = config.labelClassName;
24201
- const labelText = doc2.createElement("span");
24202
- labelText.textContent = config.labelText;
24203
- labelEl.appendChild(labelText);
24204
- container.appendChild(labelEl);
24205
- }
24206
24382
  const renderTableFragment = (deps) => {
24207
24383
  const {
24208
24384
  doc: doc2,
@@ -24346,6 +24522,7 @@ const renderTableFragment = (deps) => {
24346
24522
  renderLine,
24347
24523
  renderDrawingContent,
24348
24524
  applySdtDataset,
24525
+ tableSdt: block.attrs?.sdt ?? null,
24349
24526
  // Headers are always rendered as-is (no border suppression)
24350
24527
  continuesFromPrev: false,
24351
24528
  continuesOnNext: false
@@ -24376,6 +24553,7 @@ const renderTableFragment = (deps) => {
24376
24553
  renderLine,
24377
24554
  renderDrawingContent,
24378
24555
  applySdtDataset,
24556
+ tableSdt: block.attrs?.sdt ?? null,
24379
24557
  // Draw top border if table continues from previous fragment (MS Word behavior)
24380
24558
  continuesFromPrev: isFirstRenderedBodyRow && fragment.continuesFromPrev === true,
24381
24559
  // Draw bottom border if table continues on next fragment (MS Word behavior)
@@ -25627,8 +25805,10 @@ class DomPainter {
25627
25805
  section: "body",
25628
25806
  pageNumberText: page.numberText
25629
25807
  };
25630
- page.fragments.forEach((fragment) => {
25631
- el.appendChild(this.renderFragment(fragment, contextBase));
25808
+ const sdtBoundaries = computeSdtBoundaries(page.fragments, this.blockLookup);
25809
+ page.fragments.forEach((fragment, index2) => {
25810
+ const sdtBoundary = sdtBoundaries.get(index2);
25811
+ el.appendChild(this.renderFragment(fragment, contextBase, sdtBoundary));
25632
25812
  });
25633
25813
  this.renderDecorationsForPage(el, page);
25634
25814
  return el;
@@ -25859,6 +26039,7 @@ class DomPainter {
25859
26039
  pageEl.dataset.layoutEpoch = String(this.layoutEpoch);
25860
26040
  const existing = new Map(state.fragments.map((frag) => [frag.key, frag]));
25861
26041
  const nextFragments = [];
26042
+ const sdtBoundaries = computeSdtBoundaries(page.fragments, this.blockLookup);
25862
26043
  const contextBase = {
25863
26044
  pageNumber: page.number,
25864
26045
  totalPages: this.totalPages,
@@ -25868,11 +26049,13 @@ class DomPainter {
25868
26049
  page.fragments.forEach((fragment, index2) => {
25869
26050
  const key2 = fragmentKey(fragment);
25870
26051
  const current = existing.get(key2);
26052
+ const sdtBoundary = sdtBoundaries.get(index2);
25871
26053
  if (current) {
25872
26054
  existing.delete(key2);
25873
- const needsRebuild = this.changedBlocks.has(fragment.blockId) || current.signature !== fragmentSignature(fragment, this.blockLookup);
26055
+ const sdtBoundaryMismatch = shouldRebuildForSdtBoundary(current.element, sdtBoundary);
26056
+ const needsRebuild = this.changedBlocks.has(fragment.blockId) || current.signature !== fragmentSignature(fragment, this.blockLookup) || sdtBoundaryMismatch;
25874
26057
  if (needsRebuild) {
25875
- const replacement = this.renderFragment(fragment, contextBase);
26058
+ const replacement = this.renderFragment(fragment, contextBase, sdtBoundary);
25876
26059
  pageEl.replaceChild(replacement, current.element);
25877
26060
  current.element = replacement;
25878
26061
  current.signature = fragmentSignature(fragment, this.blockLookup);
@@ -25886,7 +26069,7 @@ class DomPainter {
25886
26069
  nextFragments.push(current);
25887
26070
  return;
25888
26071
  }
25889
- const fresh = this.renderFragment(fragment, contextBase);
26072
+ const fresh = this.renderFragment(fragment, contextBase, sdtBoundary);
25890
26073
  pageEl.insertBefore(fresh, pageEl.children[index2] ?? null);
25891
26074
  nextFragments.push({
25892
26075
  key: key2,
@@ -25958,8 +26141,10 @@ class DomPainter {
25958
26141
  totalPages: this.totalPages,
25959
26142
  section: "body"
25960
26143
  };
25961
- const fragments = page.fragments.map((fragment) => {
25962
- const fragmentEl = this.renderFragment(fragment, contextBase);
26144
+ const sdtBoundaries = computeSdtBoundaries(page.fragments, this.blockLookup);
26145
+ const fragments = page.fragments.map((fragment, index2) => {
26146
+ const sdtBoundary = sdtBoundaries.get(index2);
26147
+ const fragmentEl = this.renderFragment(fragment, contextBase, sdtBoundary);
25963
26148
  el.appendChild(fragmentEl);
25964
26149
  return {
25965
26150
  key: fragmentKey(fragment),
@@ -25979,12 +26164,12 @@ class DomPainter {
25979
26164
  }
25980
26165
  return this.options.pageStyles;
25981
26166
  }
25982
- renderFragment(fragment, context) {
26167
+ renderFragment(fragment, context, sdtBoundary) {
25983
26168
  if (fragment.kind === "para") {
25984
- return this.renderParagraphFragment(fragment, context);
26169
+ return this.renderParagraphFragment(fragment, context, sdtBoundary);
25985
26170
  }
25986
26171
  if (fragment.kind === "list-item") {
25987
- return this.renderListItemFragment(fragment, context);
26172
+ return this.renderListItemFragment(fragment, context, sdtBoundary);
25988
26173
  }
25989
26174
  if (fragment.kind === "image") {
25990
26175
  return this.renderImageFragment(fragment, context);
@@ -26003,9 +26188,10 @@ class DomPainter {
26003
26188
  *
26004
26189
  * @param fragment - The paragraph fragment to render
26005
26190
  * @param context - Rendering context with page and column information
26191
+ * @param sdtBoundary - Optional SDT boundary overrides for multi-fragment containers
26006
26192
  * @returns HTMLElement containing the rendered fragment or error placeholder
26007
26193
  */
26008
- renderParagraphFragment(fragment, context) {
26194
+ renderParagraphFragment(fragment, context, sdtBoundary) {
26009
26195
  try {
26010
26196
  const lookup = this.blockLookup.get(fragment.blockId);
26011
26197
  if (!lookup || lookup.block.kind !== "paragraph" || lookup.measure.kind !== "paragraph") {
@@ -26052,7 +26238,7 @@ class DomPainter {
26052
26238
  }
26053
26239
  this.applySdtDataset(fragmentEl, block.attrs?.sdt);
26054
26240
  this.applyContainerSdtDataset(fragmentEl, block.attrs?.containerSdt);
26055
- applySdtContainerStyling(this.doc, fragmentEl, block.attrs?.sdt, block.attrs?.containerSdt);
26241
+ applySdtContainerStyling(this.doc, fragmentEl, block.attrs?.sdt, block.attrs?.containerSdt, sdtBoundary);
26056
26242
  const dropCapDescriptor = block.attrs?.dropCapDescriptor;
26057
26243
  const dropCapMeasure = measure.dropCap;
26058
26244
  if (dropCapDescriptor && dropCapMeasure && !fragment.continuesFromPrev) {
@@ -26366,7 +26552,7 @@ class DomPainter {
26366
26552
  }
26367
26553
  return dropCapEl;
26368
26554
  }
26369
- renderListItemFragment(fragment, context) {
26555
+ renderListItemFragment(fragment, context, sdtBoundary) {
26370
26556
  try {
26371
26557
  const lookup = this.blockLookup.get(fragment.blockId);
26372
26558
  if (!lookup || lookup.block.kind !== "list" || lookup.measure.kind !== "list") {
@@ -26392,7 +26578,13 @@ class DomPainter {
26392
26578
  fragmentEl.dataset.itemId = fragment.itemId;
26393
26579
  const paragraphMetadata = item.paragraph.attrs?.sdt;
26394
26580
  this.applySdtDataset(fragmentEl, paragraphMetadata);
26395
- applySdtContainerStyling(this.doc, fragmentEl, paragraphMetadata, item.paragraph.attrs?.containerSdt);
26581
+ applySdtContainerStyling(
26582
+ this.doc,
26583
+ fragmentEl,
26584
+ paragraphMetadata,
26585
+ item.paragraph.attrs?.containerSdt,
26586
+ sdtBoundary
26587
+ );
26396
26588
  if (fragment.continuesFromPrev) {
26397
26589
  fragmentEl.dataset.continuesFromPrev = "true";
26398
26590
  }
@@ -28322,6 +28514,46 @@ class DomPainter {
28322
28514
  }
28323
28515
  }
28324
28516
  }
28517
+ const getFragmentSdtContainerKey = (fragment, blockLookup) => {
28518
+ const lookup = blockLookup.get(fragment.blockId);
28519
+ if (!lookup) return null;
28520
+ const block = lookup.block;
28521
+ if (fragment.kind === "para" && block.kind === "paragraph") {
28522
+ const attrs = block.attrs;
28523
+ return getSdtContainerKey(attrs?.sdt, attrs?.containerSdt);
28524
+ }
28525
+ if (fragment.kind === "list-item" && block.kind === "list") {
28526
+ const item = block.items.find((listItem) => listItem.id === fragment.itemId);
28527
+ const attrs = item?.paragraph.attrs;
28528
+ return getSdtContainerKey(attrs?.sdt, attrs?.containerSdt);
28529
+ }
28530
+ return null;
28531
+ };
28532
+ const computeSdtBoundaries = (fragments, blockLookup) => {
28533
+ const boundaries = /* @__PURE__ */ new Map();
28534
+ const containerKeys = fragments.map((fragment) => getFragmentSdtContainerKey(fragment, blockLookup));
28535
+ for (let i = 0; i < fragments.length; i += 1) {
28536
+ const currentKey = containerKeys[i];
28537
+ if (!currentKey) continue;
28538
+ const prev = i > 0 ? containerKeys[i - 1] : null;
28539
+ const next = i < fragments.length - 1 ? containerKeys[i + 1] : null;
28540
+ const isStart = currentKey !== prev;
28541
+ const isEnd = currentKey !== next;
28542
+ boundaries.set(i, { isStart, isEnd });
28543
+ }
28544
+ return boundaries;
28545
+ };
28546
+ const shouldRebuildForSdtBoundary = (element, boundary) => {
28547
+ if (!boundary) return false;
28548
+ const startAttr = element.dataset.sdtContainerStart;
28549
+ const endAttr = element.dataset.sdtContainerEnd;
28550
+ const expectedStart = String(boundary.isStart ?? true);
28551
+ const expectedEnd = String(boundary.isEnd ?? true);
28552
+ if (startAttr === void 0 || endAttr === void 0) {
28553
+ return true;
28554
+ }
28555
+ return startAttr !== expectedStart || endAttr !== expectedEnd;
28556
+ };
28325
28557
  const fragmentKey = (fragment) => {
28326
28558
  if (fragment.kind === "para") {
28327
28559
  return `para:${fragment.blockId}:${fragment.fromLine}:${fragment.toLine}`;
@@ -41733,16 +41965,6 @@ function tokenNodeToRun(node, positions, defaultFont, defaultSize, inheritedMark
41733
41965
  if (marksAsAttrs.length > 0) {
41734
41966
  run._explicitFont = true;
41735
41967
  }
41736
- console.debug("[token-debug] tokenNodeToRun", {
41737
- token,
41738
- fontFamily: run.fontFamily,
41739
- fontSize: run.fontSize,
41740
- defaultFont,
41741
- defaultSize,
41742
- nodeMarksCount: nodeMarks.length,
41743
- marksAsAttrsCount: marksAsAttrs.length,
41744
- inheritedMarksCount: inheritedMarks?.length ?? 0
41745
- });
41746
41968
  return run;
41747
41969
  }
41748
41970
  const EIGHTHS_PER_POINT = 8;
@@ -44138,6 +44360,16 @@ function applySdtMetadataToTableBlock(tableBlock, metadata) {
44138
44360
  table.attrs.sdt = metadata;
44139
44361
  table.rows?.forEach((row) => {
44140
44362
  row.cells?.forEach((cell) => {
44363
+ const cellBlocks = cell.blocks;
44364
+ if (cellBlocks && cellBlocks.length > 0) {
44365
+ applySdtMetadataToParagraphBlocks(cellBlocks, metadata);
44366
+ cellBlocks.forEach((block) => {
44367
+ if (block.kind === "table") {
44368
+ applySdtMetadataToTableBlock(block, metadata);
44369
+ }
44370
+ });
44371
+ return;
44372
+ }
44141
44373
  if (cell.paragraph) {
44142
44374
  applySdtMetadataToParagraphBlocks([cell.paragraph], metadata);
44143
44375
  }
@@ -45652,14 +45884,6 @@ function paragraphToFlowBlocks$1(para, nextBlockId, positions, defaultFont, defa
45652
45884
  enableComments
45653
45885
  );
45654
45886
  }
45655
- console.debug("[token-debug] paragraph-token-run", {
45656
- token: tokenRun.token,
45657
- fontFamily: tokenRun.fontFamily,
45658
- fontSize: tokenRun.fontSize,
45659
- inlineStyleId,
45660
- runStyleId: activeRunStyleId,
45661
- mergedMarksCount: mergedMarks.length
45662
- });
45663
45887
  applyInlineRunProperties(tokenRun, activeRunProperties);
45664
45888
  currentRuns.push(tokenRun);
45665
45889
  }
@@ -46315,7 +46539,19 @@ const parseTableCell = (args) => {
46315
46539
  ...cellBackgroundColor && { backgroundColor: cellBackgroundColor }
46316
46540
  } : context.converterContext;
46317
46541
  const paragraphToFlowBlocks2 = context.converters?.paragraphToFlowBlocks ?? context.paragraphToFlowBlocks;
46542
+ const tableNodeToBlock2 = context.converters?.tableNodeToBlock;
46318
46543
  const listCounterContext = context.listCounterContext;
46544
+ const appendParagraphBlocks = (paragraphBlocks, sdtMetadata) => {
46545
+ applySdtMetadataToParagraphBlocks(
46546
+ paragraphBlocks.filter((block) => block.kind === "paragraph"),
46547
+ sdtMetadata
46548
+ );
46549
+ paragraphBlocks.forEach((block) => {
46550
+ if (block.kind === "paragraph" || block.kind === "image" || block.kind === "drawing") {
46551
+ blocks.push(block);
46552
+ }
46553
+ });
46554
+ };
46319
46555
  for (const childNode of cellNode.content) {
46320
46556
  if (childNode.type === "paragraph") {
46321
46557
  if (!paragraphToFlowBlocks2) continue;
@@ -46333,11 +46569,75 @@ const parseTableCell = (args) => {
46333
46569
  context.themeColors,
46334
46570
  cellConverterContext
46335
46571
  );
46336
- paragraphBlocks.forEach((block) => {
46337
- if (block.kind === "paragraph" || block.kind === "image" || block.kind === "drawing") {
46338
- blocks.push(block);
46572
+ appendParagraphBlocks(paragraphBlocks);
46573
+ continue;
46574
+ }
46575
+ if (childNode.type === "structuredContentBlock" && Array.isArray(childNode.content)) {
46576
+ const structuredContentMetadata = resolveNodeSdtMetadata(childNode, "structuredContentBlock");
46577
+ for (const nestedNode of childNode.content) {
46578
+ if (nestedNode.type === "paragraph") {
46579
+ if (!paragraphToFlowBlocks2) continue;
46580
+ const paragraphBlocks = paragraphToFlowBlocks2(
46581
+ nestedNode,
46582
+ context.nextBlockId,
46583
+ context.positions,
46584
+ context.defaultFont,
46585
+ context.defaultSize,
46586
+ context.styleContext,
46587
+ listCounterContext,
46588
+ context.trackedChanges,
46589
+ context.bookmarks,
46590
+ context.hyperlinkConfig,
46591
+ context.themeColors,
46592
+ cellConverterContext
46593
+ );
46594
+ appendParagraphBlocks(paragraphBlocks, structuredContentMetadata);
46595
+ continue;
46339
46596
  }
46340
- });
46597
+ if (nestedNode.type === "table" && tableNodeToBlock2) {
46598
+ const tableBlock = tableNodeToBlock2(
46599
+ nestedNode,
46600
+ context.nextBlockId,
46601
+ context.positions,
46602
+ context.defaultFont,
46603
+ context.defaultSize,
46604
+ context.styleContext,
46605
+ context.trackedChanges,
46606
+ context.bookmarks,
46607
+ context.hyperlinkConfig,
46608
+ context.themeColors,
46609
+ paragraphToFlowBlocks2,
46610
+ context.converterContext,
46611
+ { listCounterContext, converters: context.converters }
46612
+ );
46613
+ if (tableBlock && tableBlock.kind === "table") {
46614
+ applySdtMetadataToTableBlock(tableBlock, structuredContentMetadata);
46615
+ blocks.push(tableBlock);
46616
+ }
46617
+ continue;
46618
+ }
46619
+ }
46620
+ continue;
46621
+ }
46622
+ if (childNode.type === "table" && tableNodeToBlock2) {
46623
+ const tableBlock = tableNodeToBlock2(
46624
+ childNode,
46625
+ context.nextBlockId,
46626
+ context.positions,
46627
+ context.defaultFont,
46628
+ context.defaultSize,
46629
+ context.styleContext,
46630
+ context.trackedChanges,
46631
+ context.bookmarks,
46632
+ context.hyperlinkConfig,
46633
+ context.themeColors,
46634
+ paragraphToFlowBlocks2,
46635
+ context.converterContext,
46636
+ { listCounterContext, converters: context.converters }
46637
+ );
46638
+ if (tableBlock && tableBlock.kind === "table") {
46639
+ blocks.push(tableBlock);
46640
+ }
46341
46641
  continue;
46342
46642
  }
46343
46643
  if (childNode.type === "image" && context.converters?.imageNodeToBlock) {
@@ -46401,6 +46701,7 @@ const parseTableCell = (args) => {
46401
46701
  if (drawingBlock && drawingBlock.kind === "drawing") {
46402
46702
  blocks.push(drawingBlock);
46403
46703
  }
46704
+ continue;
46404
46705
  }
46405
46706
  }
46406
46707
  if (blocks.length === 0) {
@@ -51944,6 +52245,39 @@ class PresentationEditor extends EventEmitter {
51944
52245
  height: rect.height
51945
52246
  };
51946
52247
  }
52248
+ /**
52249
+ * Get the painted DOM element that contains a document position (body only).
52250
+ *
52251
+ * Uses the DomPositionIndex which maps data-pm-start/end attributes to rendered
52252
+ * elements. Returns null when the position is not currently mounted (virtualization)
52253
+ * or when in header/footer mode.
52254
+ *
52255
+ * @param pos - Document position in the active editor
52256
+ * @param options.forceRebuild - Rebuild the index before lookup
52257
+ * @param options.fallbackToCoords - Use elementFromPoint with layout rects if index lookup fails
52258
+ * @returns The nearest painted DOM element for the position, or null if unavailable
52259
+ */
52260
+ getElementAtPos(pos, options = {}) {
52261
+ if (!Number.isFinite(pos)) return null;
52262
+ if (!this.#painterHost) return null;
52263
+ if (this.#session.mode !== "body") return null;
52264
+ if (options.forceRebuild || this.#domPositionIndex.size === 0) {
52265
+ this.#rebuildDomPositionIndex();
52266
+ }
52267
+ const indexed = this.#domPositionIndex.findElementAtPosition(pos);
52268
+ if (indexed) return indexed;
52269
+ if (!options.fallbackToCoords) return null;
52270
+ const rects = this.getRangeRects(pos, pos);
52271
+ if (!rects.length) return null;
52272
+ const doc2 = this.#visibleHost.ownerDocument ?? document;
52273
+ for (const rect of rects) {
52274
+ const el = doc2.elementFromPoint(rect.left + rect.width / 2, rect.top + rect.height / 2);
52275
+ if (el instanceof HTMLElement && this.#painterHost.contains(el)) {
52276
+ return el.closest("[data-pm-start][data-pm-end]") ?? el;
52277
+ }
52278
+ }
52279
+ return null;
52280
+ }
51947
52281
  /**
51948
52282
  * Scroll the visible host so a given document position is brought into view.
51949
52283
  *