@superdoc-dev/cli 0.16.0-next.28 → 0.16.0-next.29

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 +1348 -174
  2. package/package.json +6 -6
package/dist/index.js CHANGED
@@ -3382,7 +3382,7 @@ More content with **bold** and *italic*.`
3382
3382
  "trackChanges.list": {
3383
3383
  memberPath: "trackChanges.list",
3384
3384
  description: "List all tracked changes in the document.",
3385
- expectedResult: "Returns a TrackChangesListResult with tracked change entries (`insert`, `delete`, `replacement`, `format`), total count, and raw imported Word OOXML revision IDs (`w:id`) when available.",
3385
+ expectedResult: "Returns a TrackChangesListResult with tracked change entries (`insert`, `delete`, `replacement`, `format`, `structural`), total count, and raw imported Word OOXML revision IDs (`w:id`) when available. Structural changes (whole-table insert/delete) carry a `subtype` of `table-insert` or `table-delete`.",
3386
3386
  requiresDocumentContext: true,
3387
3387
  metadata: readOperation({
3388
3388
  idempotency: "idempotent",
@@ -3396,7 +3396,7 @@ More content with **bold** and *italic*.`
3396
3396
  "trackChanges.get": {
3397
3397
  memberPath: "trackChanges.get",
3398
3398
  description: "Retrieve a single tracked change by ID.",
3399
- expectedResult: "Returns a TrackChangeInfo object with the change type (`insert`, `delete`, `replacement`, `format`), author, date, affected content, and raw imported Word OOXML revision IDs (`w:id`) when available.",
3399
+ expectedResult: "Returns a TrackChangeInfo object with the change type (`insert`, `delete`, `replacement`, `format`, `structural`), author, date, affected content, and raw imported Word OOXML revision IDs (`w:id`) when available. Structural changes (whole-table insert/delete) carry a `subtype` of `table-insert` or `table-delete`.",
3400
3400
  requiresDocumentContext: true,
3401
3401
  metadata: readOperation({
3402
3402
  idempotency: "idempotent",
@@ -8780,7 +8780,7 @@ var init_schemas = __esm(() => {
8780
8780
  init_style_policy_types();
8781
8781
  init_paragraphs();
8782
8782
  init_styles();
8783
- trackChangeTypeValues = ["insert", "delete", "replacement", "format"];
8783
+ trackChangeTypeValues = ["insert", "delete", "replacement", "format", "structural"];
8784
8784
  nodeTypeValues = NODE_TYPES;
8785
8785
  blockNodeTypeValues = BLOCK_NODE_TYPES;
8786
8786
  deletableBlockNodeTypeValues = DELETABLE_BLOCK_NODE_TYPES;
@@ -9550,6 +9550,10 @@ var init_schemas = __esm(() => {
9550
9550
  address: trackedChangeAddressSchema,
9551
9551
  id: { type: "string" },
9552
9552
  type: { enum: [...trackChangeTypeValues] },
9553
+ subtype: {
9554
+ enum: ["table-insert", "table-delete"],
9555
+ description: "Finer classification for structural changes (type === 'structural')."
9556
+ },
9553
9557
  grouping: { enum: ["standalone", "replacement-pair", "unknown"] },
9554
9558
  pairedWithChangeId: { type: ["string", "null"] },
9555
9559
  wordRevisionIds: trackChangeWordRevisionIdsSchema,
@@ -9564,6 +9568,10 @@ var init_schemas = __esm(() => {
9564
9568
  trackChangeDomainItemSchema = discoveryItemSchema({
9565
9569
  address: trackedChangeAddressSchema,
9566
9570
  type: { enum: [...trackChangeTypeValues] },
9571
+ subtype: {
9572
+ enum: ["table-insert", "table-delete"],
9573
+ description: "Finer classification for structural changes (type === 'structural')."
9574
+ },
9567
9575
  grouping: { enum: ["standalone", "replacement-pair", "unknown"] },
9568
9576
  pairedWithChangeId: { type: ["string", "null"] },
9569
9577
  wordRevisionIds: trackChangeWordRevisionIdsSchema,
@@ -11877,7 +11885,7 @@ var init_schemas = __esm(() => {
11877
11885
  offset: { type: "integer", description: "Number of tracked changes to skip for pagination." },
11878
11886
  type: {
11879
11887
  enum: [...trackChangeTypeValues],
11880
- description: "Filter by change type: 'insert', 'delete', 'replacement', or 'format'."
11888
+ description: "Filter by change type: 'insert', 'delete', 'replacement', 'format', or 'structural'."
11881
11889
  },
11882
11890
  in: {
11883
11891
  oneOf: [storyLocatorSchema, { const: "all" }],
@@ -11897,7 +11905,14 @@ var init_schemas = __esm(() => {
11897
11905
  decision: { enum: ["accept", "reject"] },
11898
11906
  target: {
11899
11907
  oneOf: [
11900
- objectSchema({ id: { type: "string" }, story: storyLocatorSchema }, ["id"]),
11908
+ objectSchema({
11909
+ id: { type: "string" },
11910
+ story: storyLocatorSchema,
11911
+ range: {
11912
+ type: "object",
11913
+ description: "Partial-range qualifier on an id target. Rejected with INVALID_INPUT for indivisible (e.g. structural) revisions."
11914
+ }
11915
+ }, ["id"]),
11901
11916
  objectSchema({
11902
11917
  kind: { const: "range" },
11903
11918
  range: textTargetSchema,
@@ -16749,6 +16764,16 @@ function executeTrackChangesDecide(adapter, rawInput, options) {
16749
16764
  if (rawStory === "all") {
16750
16765
  throw new DocumentApiValidationError("INVALID_TARGET", 'trackChanges.decide id targets do not support story: "all".', { field: "target.story", value: rawStory });
16751
16766
  }
16767
+ if (target.range !== undefined) {
16768
+ return {
16769
+ success: false,
16770
+ failure: {
16771
+ code: "INVALID_INPUT",
16772
+ message: "trackChanges.decide does not support a partial range on an id target; the change is not safely divisible.",
16773
+ details: { target: input.target }
16774
+ }
16775
+ };
16776
+ }
16752
16777
  if (typeof target.id !== "string" || target.id.length === 0) {
16753
16778
  throw new DocumentApiValidationError("INVALID_TARGET", "trackChanges.decide id targets require a non-empty id.", {
16754
16779
  field: "target",
@@ -68348,7 +68373,7 @@ var init_remark_gfm_BhnWr3yf_es = __esm(() => {
68348
68373
  emptyOptions2 = {};
68349
68374
  });
68350
68375
 
68351
- // ../../packages/superdoc/dist/chunks/SuperConverter-D2zNnC50.es.js
68376
+ // ../../packages/superdoc/dist/chunks/SuperConverter-BBjNvGFh.es.js
68352
68377
  function getExtensionConfigField(extension$1, field, context = { name: "" }) {
68353
68378
  const fieldValue = extension$1.config[field];
68354
68379
  if (typeof fieldValue === "function")
@@ -72914,6 +72939,15 @@ function executeTrackChangesDecide2(adapter, rawInput, options) {
72914
72939
  field: "target.story",
72915
72940
  value: rawStory
72916
72941
  });
72942
+ if (target.range !== undefined)
72943
+ return {
72944
+ success: false,
72945
+ failure: {
72946
+ code: "INVALID_INPUT",
72947
+ message: "trackChanges.decide does not support a partial range on an id target; the change is not safely divisible.",
72948
+ details: { target: input.target }
72949
+ }
72950
+ };
72917
72951
  if (typeof target.id !== "string" || target.id.length === 0)
72918
72952
  throw new DocumentApiValidationError2("INVALID_TARGET", "trackChanges.decide id targets require a non-empty id.", {
72919
72953
  field: "target",
@@ -81365,6 +81399,61 @@ function decode$50(params3, decodedAttrs) {
81365
81399
  };
81366
81400
  return translated;
81367
81401
  }
81402
+ function readRowTrackChange(trPr, params3 = {}) {
81403
+ const marker = trPr?.elements?.find((el) => el.name === "w:ins" || el.name === "w:del");
81404
+ if (!marker)
81405
+ return null;
81406
+ const side = marker.name === "w:ins" ? "insertion" : "deletion";
81407
+ const attributes = marker.attributes || {};
81408
+ const { sourceId, logicalId } = resolveTrackedChangeImportIds(params3, attributes["w:id"]);
81409
+ const trackChange = {
81410
+ type: side === "insertion" ? "rowInsert" : "rowDelete",
81411
+ id: logicalId,
81412
+ sourceId,
81413
+ author: attributes["w:author"] || "",
81414
+ authorEmail: attributes["w:authorEmail"] || "",
81415
+ date: attributes["w:date"] || "",
81416
+ importedAuthor: `${attributes["w:author"] || ""} (imported)`
81417
+ };
81418
+ stampImportTrackingAttrs({
81419
+ params: params3,
81420
+ attrs: trackChange,
81421
+ side,
81422
+ sourceId
81423
+ });
81424
+ return trackChange;
81425
+ }
81426
+ function buildRowTrackChangeElement(trackChange, params3 = {}) {
81427
+ if (!trackChange || trackChange.type !== "rowInsert" && trackChange.type !== "rowDelete")
81428
+ return null;
81429
+ const name = trackChange.type === "rowInsert" ? "w:ins" : "w:del";
81430
+ const wId = resolveExportRowWordId(params3, trackChange);
81431
+ const attributes = { "w:id": wId };
81432
+ if (trackChange.author)
81433
+ attributes["w:author"] = trackChange.author;
81434
+ if (trackChange.authorEmail)
81435
+ attributes["w:authorEmail"] = trackChange.authorEmail;
81436
+ if (trackChange.date)
81437
+ attributes["w:date"] = trackChange.date;
81438
+ return {
81439
+ name,
81440
+ attributes
81441
+ };
81442
+ }
81443
+ function resolveExportRowWordId(params3, trackChange) {
81444
+ const sourceId = trackChange.sourceId;
81445
+ const logicalId = typeof trackChange.id === "string" ? trackChange.id : "";
81446
+ const exportParams = params3;
81447
+ const allocator = exportParams?.converter?.wordIdAllocator;
81448
+ const partPath = exportParams?.currentPartPath || (typeof exportParams?.filename === "string" && exportParams.filename.length > 0 ? `word/${exportParams.filename}` : "word/document.xml");
81449
+ if (allocator)
81450
+ return allocator.allocate({
81451
+ partPath,
81452
+ sourceId: sourceId === undefined ? undefined : sourceId === null ? null : String(sourceId),
81453
+ logicalId
81454
+ });
81455
+ return String(sourceId || logicalId || "");
81456
+ }
81368
81457
  function parseTagValueJSON(json) {
81369
81458
  if (typeof json !== "string")
81370
81459
  return {};
@@ -105928,8 +106017,10 @@ function tableNodeToBlock(node3, { nextBlockId, positions, storyKey, trackedChan
105928
106017
  defaultCellPadding,
105929
106018
  tableProperties: tablePropertiesForCascade
105930
106019
  });
105931
- if (parsedRow)
105932
- rows.push(parsedRow);
106020
+ if (parsedRow) {
106021
+ if (!shouldHideTrackedNode(parsedRow.attrs?.trackedChange, parserDeps.trackedChangesConfig))
106022
+ rows.push(parsedRow);
106023
+ }
105933
106024
  });
105934
106025
  if (rows.length === 0)
105935
106026
  return null;
@@ -110819,6 +110910,8 @@ function deriveTrackedChangeId(change) {
110819
110910
  return change.rawId;
110820
110911
  }
110821
110912
  function resolveTrackedChangeType(change) {
110913
+ if (change.structural)
110914
+ return "structural";
110822
110915
  if (change.hasFormat)
110823
110916
  return "format";
110824
110917
  if (change.hasInsert && change.hasDelete)
@@ -111054,6 +111147,42 @@ function groupTrackedChanges(editor) {
111054
111147
  return a.id.localeCompare(b.id);
111055
111148
  });
111056
111149
  attachOverlapMetadata(grouped);
111150
+ for (const structural of enumerateStructuralRowChanges(editor.state)) {
111151
+ const excerpt = normalizeExcerpt(editor.state.doc.textBetween(structural.tableFrom, structural.tableTo, " ", ""));
111152
+ const stableRawId = structural.sourceId ? `word:structural:${structural.sourceId}` : structural.id;
111153
+ grouped.push({
111154
+ rawId: stableRawId,
111155
+ commandRawId: structural.id,
111156
+ id: stableRawId,
111157
+ from: structural.tableFrom,
111158
+ to: structural.tableTo,
111159
+ hasInsert: false,
111160
+ hasDelete: false,
111161
+ hasFormat: false,
111162
+ structural: {
111163
+ side: structural.side,
111164
+ subtype: structural.subtype
111165
+ },
111166
+ attrs: {
111167
+ id: structural.id,
111168
+ sourceId: structural.sourceId || undefined,
111169
+ author: structural.author || undefined,
111170
+ authorEmail: structural.authorEmail || undefined,
111171
+ authorImage: structural.authorImage || undefined,
111172
+ date: structural.date || undefined,
111173
+ importedAuthor: structural.importedAuthor || undefined,
111174
+ origin: structural.sourceId ? "word" : undefined,
111175
+ revisionGroupId: structural.revisionGroupId || undefined
111176
+ },
111177
+ excerpt,
111178
+ wordRevisionIds: structural.sourceId ? structural.side === "insertion" ? { insert: structural.sourceId } : { delete: structural.sourceId } : undefined
111179
+ });
111180
+ }
111181
+ grouped.sort((a, b) => {
111182
+ if (a.from !== b.from)
111183
+ return a.from - b.from;
111184
+ return a.id.localeCompare(b.id);
111185
+ });
111057
111186
  groupedCache.set(editor, {
111058
111187
  doc: currentDoc,
111059
111188
  grouped
@@ -114947,13 +115076,16 @@ var isRegExp = (value) => {
114947
115076
  stampBlockTrackedChangeColors(item.paragraph, resolve2);
114948
115077
  break;
114949
115078
  case "table":
114950
- for (const row of block.rows)
115079
+ for (const row of block.rows) {
115080
+ if (row.attrs?.trackedChange)
115081
+ applyColorToLayer(row.attrs.trackedChange, resolve2);
114951
115082
  for (const cell of row.cells) {
114952
115083
  stampBlockTrackedChangeColors(cell.paragraph, resolve2);
114953
115084
  if (Array.isArray(cell.blocks))
114954
115085
  for (const nested of cell.blocks)
114955
115086
  stampBlockTrackedChangeColors(nested, resolve2);
114956
115087
  }
115088
+ }
114957
115089
  break;
114958
115090
  default:
114959
115091
  break;
@@ -115910,6 +116042,9 @@ var isRegExp = (value) => {
115910
116042
  ...params3,
115911
116043
  nodes: [tPr]
115912
116044
  });
116045
+ const trackChange = readRowTrackChange(tPr, params3);
116046
+ if (trackChange)
116047
+ encodedAttrs["trackChange"] = trackChange;
115913
116048
  const gridBeforeRaw = tableRowProperties?.["gridBefore"];
115914
116049
  const safeGridBefore = typeof gridBeforeRaw === "number" && Number.isFinite(gridBeforeRaw) && gridBeforeRaw > 0 ? gridBeforeRaw : 0;
115915
116050
  const tblPrExBorders = row.elements?.find((el) => el.name === "w:tblPrEx")?.elements?.find((el) => el.name === "w:tblBorders");
@@ -116099,11 +116234,115 @@ var isRegExp = (value) => {
116099
116234
  if (trPr)
116100
116235
  elements.unshift(trPr);
116101
116236
  }
116237
+ applyRowTrackChangeOnDecode({
116238
+ node: node3,
116239
+ elements,
116240
+ params: params3
116241
+ });
116102
116242
  return {
116103
116243
  name: "w:tr",
116104
116244
  attributes: decodedAttrs || {},
116105
116245
  elements
116106
116246
  };
116247
+ }, applyRowTrackChangeOnDecode = ({ node: node3, elements, params: params3 }) => {
116248
+ const marker = buildRowTrackChangeElement(node3.attrs?.trackChange, params3);
116249
+ if (!marker)
116250
+ return;
116251
+ let trPr = elements.find((el) => el && el.name === "w:trPr");
116252
+ if (!trPr) {
116253
+ trPr = {
116254
+ name: "w:trPr",
116255
+ elements: []
116256
+ };
116257
+ elements.unshift(trPr);
116258
+ }
116259
+ if (!Array.isArray(trPr.elements))
116260
+ trPr.elements = [];
116261
+ const trPrChangeIndex = trPr.elements.findIndex((el) => el && el.name === "w:trPrChange");
116262
+ if (trPrChangeIndex === -1)
116263
+ trPr.elements.push(marker);
116264
+ else
116265
+ trPr.elements.splice(trPrChangeIndex, 0, marker);
116266
+ applyCellContentTrackChange({
116267
+ elements,
116268
+ markerName: marker.name,
116269
+ markerAttributes: marker.attributes
116270
+ });
116271
+ }, applyCellContentTrackChange = ({ elements, markerName, markerAttributes }) => {
116272
+ if (markerName !== "w:ins" && markerName !== "w:del")
116273
+ return;
116274
+ const isDelete = markerName === "w:del";
116275
+ const makeMarker = (children) => ({
116276
+ name: markerName,
116277
+ attributes: { ...markerAttributes },
116278
+ elements: children
116279
+ });
116280
+ const RUN_CONTAINERS = new Set([
116281
+ "w:hyperlink",
116282
+ "w:smartTag",
116283
+ "w:sdt",
116284
+ "w:sdtContent",
116285
+ "w:dir",
116286
+ "w:bdo"
116287
+ ]);
116288
+ const wrapRuns = (content$2) => (Array.isArray(content$2) ? content$2 : []).map((el) => {
116289
+ if (!el || typeof el !== "object")
116290
+ return el;
116291
+ if (el.name === "w:r") {
116292
+ if (isDelete && Array.isArray(el.elements))
116293
+ el.elements = el.elements.map((child) => child?.name === "w:t" ? {
116294
+ ...child,
116295
+ name: "w:delText"
116296
+ } : child);
116297
+ return makeMarker([el]);
116298
+ }
116299
+ if (RUN_CONTAINERS.has(el.name) && Array.isArray(el.elements))
116300
+ return {
116301
+ ...el,
116302
+ elements: wrapRuns(el.elements)
116303
+ };
116304
+ return el;
116305
+ });
116306
+ for (const tc of elements) {
116307
+ if (tc?.name !== "w:tc" || !Array.isArray(tc.elements))
116308
+ continue;
116309
+ for (const paragraph2 of tc.elements) {
116310
+ if (paragraph2?.name !== "w:p")
116311
+ continue;
116312
+ if (!Array.isArray(paragraph2.elements))
116313
+ paragraph2.elements = [];
116314
+ let pPr = paragraph2.elements.find((el) => el?.name === "w:pPr");
116315
+ if (!pPr) {
116316
+ pPr = {
116317
+ name: "w:pPr",
116318
+ elements: []
116319
+ };
116320
+ paragraph2.elements.unshift(pPr);
116321
+ }
116322
+ if (!Array.isArray(pPr.elements))
116323
+ pPr.elements = [];
116324
+ let rPr = pPr.elements.find((el) => el?.name === "w:rPr");
116325
+ if (!rPr) {
116326
+ rPr = {
116327
+ name: "w:rPr",
116328
+ elements: []
116329
+ };
116330
+ const terminalIdx = pPr.elements.findIndex((el) => el?.name === "w:sectPr" || el?.name === "w:pPrChange");
116331
+ if (terminalIdx === -1)
116332
+ pPr.elements.push(rPr);
116333
+ else
116334
+ pPr.elements.splice(terminalIdx, 0, rPr);
116335
+ }
116336
+ if (!Array.isArray(rPr.elements))
116337
+ rPr.elements = [];
116338
+ if (!rPr.elements.some((el) => el?.name === "w:ins" || el?.name === "w:del"))
116339
+ rPr.elements.unshift({
116340
+ name: markerName,
116341
+ attributes: { ...markerAttributes }
116342
+ });
116343
+ paragraph2.elements = wrapRuns(paragraph2.elements);
116344
+ }
116345
+ }
116107
116346
  }, config$30, translator$8, parseAnnotationMarks = (content$2 = {}) => {
116108
116347
  const rPr = content$2.elements?.find((el) => el.name === "w:r")?.elements?.find((el) => el.name === "w:rPr");
116109
116348
  if (!rPr)
@@ -129645,7 +129884,12 @@ var isRegExp = (value) => {
129645
129884
  writingMode,
129646
129885
  rtlGutter
129647
129886
  };
129648
- }, browser2, process3, cachedSetTimeout2, cachedClearTimeout2, queue2, draining2 = false, currentQueue2, queueIndex2 = -1, browserExports2, process$12, TWIPS_PER_INCH$1 = 1440, PX_PER_PT, VALID_TRACKED_MODES, DEFAULT_HYPERLINK_CONFIG, ATOMIC_INLINE_TYPES, TOKEN_INLINE_TYPES, isValidTrackedMode = (value) => {
129887
+ }, browser2, process3, cachedSetTimeout2, cachedClearTimeout2, queue2, draining2 = false, currentQueue2, queueIndex2 = -1, browserExports2, process$12, TWIPS_PER_INCH$1 = 1440, PX_PER_PT, VALID_TRACKED_MODES, DEFAULT_HYPERLINK_CONFIG, ATOMIC_INLINE_TYPES, TOKEN_INLINE_TYPES, RANDOM_ID_LENGTH$1 = 9, generateRandomBase36Id$1 = (length3) => {
129888
+ let randomId = "";
129889
+ while (randomId.length < length3)
129890
+ randomId += Math.random().toString(36).slice(2);
129891
+ return randomId.slice(0, length3);
129892
+ }, isValidTrackedMode = (value) => {
129649
129893
  return typeof value === "string" && VALID_TRACKED_MODES.includes(value);
129650
129894
  }, isTextRun$2 = (run$1) => {
129651
129895
  return "text" in run$1 && run$1.kind !== "tab";
@@ -129654,6 +129898,10 @@ var isRegExp = (value) => {
129654
129898
  delete run$1.trackedChange;
129655
129899
  if ("trackedChanges" in run$1 && run$1.trackedChanges)
129656
129900
  delete run$1.trackedChanges;
129901
+ }, deriveTrackedChangeId$1 = (kind, attrs) => {
129902
+ if (attrs && typeof attrs.id === "string" && attrs.id.trim())
129903
+ return attrs.id;
129904
+ return `${kind}-${attrs && typeof attrs.authorEmail === "string" ? attrs.authorEmail : "unknown"}-${attrs && typeof attrs.date === "string" ? attrs.date : "unknown"}-${`${Date.now()}-${generateRandomBase36Id$1(RANDOM_ID_LENGTH$1)}`}`;
129657
129905
  }, normalizeTrackedChangeLayers$1 = (run$1) => {
129658
129906
  if (Array.isArray(run$1.trackedChanges) && run$1.trackedChanges.length > 0)
129659
129907
  return run$1.trackedChanges;
@@ -130999,7 +131247,7 @@ var isRegExp = (value) => {
130999
131247
  return normalized.length ? normalized : undefined;
131000
131248
  }, pickTrackedChangeKind = (markType) => {
131001
131249
  return TRACK_CHANGE_KIND_MAP[markType];
131002
- }, deriveTrackedChangeId$1 = (kind, attrs) => {
131250
+ }, deriveTrackedChangeId$2 = (kind, attrs) => {
131003
131251
  if (attrs && typeof attrs.id === "string" && attrs.id.trim())
131004
131252
  return attrs.id;
131005
131253
  return `${kind}-${attrs && typeof attrs.authorEmail === "string" ? attrs.authorEmail : "unknown"}-${attrs && typeof attrs.date === "string" ? attrs.date : "unknown"}-${`${Date.now()}-${generateRandomBase36Id(RANDOM_ID_LENGTH)}`}`;
@@ -131010,7 +131258,7 @@ var isRegExp = (value) => {
131010
131258
  const attrs = mark.attrs ?? {};
131011
131259
  const meta = {
131012
131260
  kind,
131013
- id: deriveTrackedChangeId$1(kind, attrs)
131261
+ id: deriveTrackedChangeId$2(kind, attrs)
131014
131262
  };
131015
131263
  if (typeof attrs.overlapParentId === "string" && attrs.overlapParentId) {
131016
131264
  meta.overlapParentId = attrs.overlapParentId;
@@ -132404,6 +132652,27 @@ var isRegExp = (value) => {
132404
132652
  attrs: Object.keys(cellAttrs).length > 0 ? cellAttrs : undefined,
132405
132653
  sourceAnchor: sourceAnchorFromNode$1(cellNode)
132406
132654
  };
132655
+ }, buildRowTrackedChangeMeta = (rowNode, storyKey) => {
132656
+ const trackChange = rowNode.attrs?.trackChange;
132657
+ if (!trackChange || typeof trackChange !== "object")
132658
+ return;
132659
+ const rawType = trackChange.type;
132660
+ if (rawType !== "rowInsert" && rawType !== "rowDelete")
132661
+ return;
132662
+ const kind = rawType === "rowInsert" ? "insert" : "delete";
132663
+ const meta = {
132664
+ kind,
132665
+ id: deriveTrackedChangeId$1(kind, trackChange)
132666
+ };
132667
+ if (typeof trackChange.author === "string" && trackChange.author)
132668
+ meta.author = trackChange.author;
132669
+ if (typeof trackChange.authorEmail === "string" && trackChange.authorEmail)
132670
+ meta.authorEmail = trackChange.authorEmail;
132671
+ if (typeof trackChange.date === "string" && trackChange.date)
132672
+ meta.date = trackChange.date;
132673
+ if (typeof storyKey === "string" && storyKey.length > 0)
132674
+ meta.storyKey = storyKey;
132675
+ return meta;
132407
132676
  }, parseTableRow = (args2) => {
132408
132677
  const { rowNode, rowIndex, context, defaultCellPadding, tableProperties, numRows } = args2;
132409
132678
  if (!isTableRowNode(rowNode) || !Array.isArray(rowNode.content))
@@ -132431,13 +132700,19 @@ var isRegExp = (value) => {
132431
132700
  return null;
132432
132701
  const rowProps = rowNode.attrs?.tableRowProperties;
132433
132702
  const rowHeight = normalizeRowHeight(rowProps);
132703
+ const trackedChangesConfig = context.trackedChangesConfig;
132704
+ const rowTrackedChange = trackedChangesConfig?.enabled && trackedChangesConfig.mode !== "off" ? buildRowTrackedChangeMeta(rowNode, context.storyKey) : undefined;
132434
132705
  const tblPrExBordersRaw = rowProps?.tblPrExBorders;
132435
132706
  const rowBorders = tblPrExBordersRaw && typeof tblPrExBordersRaw === "object" ? extractTableBorders(tblPrExBordersRaw, { unit: "eighthPoints" }) : undefined;
132436
132707
  const attrs = rowProps && typeof rowProps === "object" ? {
132437
132708
  tableRowProperties: rowProps,
132438
132709
  ...rowHeight ? { rowHeight } : {},
132710
+ ...rowTrackedChange ? { trackedChange: rowTrackedChange } : {},
132439
132711
  ...rowBorders ? { borders: rowBorders } : {}
132440
- } : rowHeight ? { rowHeight } : undefined;
132712
+ } : rowHeight || rowTrackedChange ? {
132713
+ ...rowHeight ? { rowHeight } : {},
132714
+ ...rowTrackedChange ? { trackedChange: rowTrackedChange } : {}
132715
+ } : undefined;
132441
132716
  return {
132442
132717
  id: context.nextBlockId(`row-${rowIndex}`),
132443
132718
  cells,
@@ -132719,7 +132994,109 @@ var isRegExp = (value) => {
132719
132994
  if (id2)
132720
132995
  return trackedChanges.filter(({ mark }) => mark.attrs.id === id2);
132721
132996
  return trackedChanges;
132722
- }, groupedCache, SDT_NODE_NAMES, SDT_BLOCK_NAME = "structuredContentBlock", SDT_INLINE_NAME = "structuredContent", SDT_NODE_TYPES, VALID_CONTROL_TYPES, VALID_LOCK_MODES2, VALID_APPEARANCES, FIELD_LIKE_SDT_TYPES, liveDocumentCountsCache, BIBLIOGRAPHY_NAMESPACE_URI = "http://schemas.openxmlformats.org/officeDocument/2006/bibliography", CUSTOM_XML_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml", CUSTOM_XML_PROPS_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps", DEFAULT_SELECTED_STYLE = "/APA.XSL", DEFAULT_STYLE_NAME = "APA", DEFAULT_VERSION = "6", API_TO_OOXML_SOURCE_TYPE, OOXML_TO_API_SOURCE_TYPE, SIMPLE_FIELD_TO_XML_TAG, XML_TAG_TO_SIMPLE_FIELD, import_lib2, FONT_FAMILY_FALLBACKS, DEFAULT_GENERIC_FALLBACK = "sans-serif", DEFAULT_FONT_SIZE_PT = 10, CURRENT_APP_VERSION = "1.38.0", SUPERDOC_DOCUMENT_ORIGIN_PROPERTY = "SuperdocDocumentOrigin", STORED_DOCUMENT_ORIGINS, collectRunDefaultProperties = (runProps, { allowOverrideTypeface = true, allowOverrideSize = true, themeResolver, state }) => {
132997
+ }, enumerateStructuralRowChanges = (state) => {
132998
+ const doc$2 = state?.doc;
132999
+ if (!doc$2)
133000
+ return [];
133001
+ const out = [];
133002
+ try {
133003
+ doc$2.descendants((node3, pos) => {
133004
+ if (node3.type?.name !== "table")
133005
+ return;
133006
+ collectTableStructuralChanges({
133007
+ table: node3,
133008
+ tablePos: pos,
133009
+ out
133010
+ });
133011
+ return true;
133012
+ });
133013
+ } catch {
133014
+ return out;
133015
+ }
133016
+ return out;
133017
+ }, collectTableStructuralChanges = ({ table, tablePos, out }) => {
133018
+ const tableFrom = tablePos;
133019
+ const tableTo = tablePos + table.nodeSize;
133020
+ const trackedRows = [];
133021
+ let totalRows = 0;
133022
+ let offset = 1;
133023
+ table.forEach((child) => {
133024
+ const childFrom = tablePos + offset;
133025
+ offset += child.nodeSize;
133026
+ if (child.type?.name !== "tableRow")
133027
+ return;
133028
+ totalRows += 1;
133029
+ const tc = child.attrs?.trackChange;
133030
+ if (!tc || tc.type !== "rowInsert" && tc.type !== "rowDelete")
133031
+ return;
133032
+ const side$1 = tc.type === "rowInsert" ? "insertion" : "deletion";
133033
+ trackedRows.push({
133034
+ ref: {
133035
+ pos: childFrom,
133036
+ from: childFrom,
133037
+ to: childFrom + child.nodeSize,
133038
+ node: child
133039
+ },
133040
+ side: side$1,
133041
+ tc
133042
+ });
133043
+ });
133044
+ if (trackedRows.length === 0)
133045
+ return;
133046
+ const sides = new Set(trackedRows.map((r) => r.side));
133047
+ const everyRowTracked = trackedRows.length === totalRows && totalRows > 0;
133048
+ const singleSide = sides.size === 1;
133049
+ if (everyRowTracked && singleSide) {
133050
+ const side$1 = trackedRows[0].side;
133051
+ const primary$1 = trackedRows[0].tc;
133052
+ const representativeRevisionId$1 = stringOf(primary$1.id) || stringOf(primary$1.sourceId);
133053
+ const publicId = stringOf(primary$1.sourceId) || representativeRevisionId$1 || `table:${tableFrom}:${side$1}`;
133054
+ out.push({
133055
+ id: publicId,
133056
+ revisionId: representativeRevisionId$1,
133057
+ side: side$1,
133058
+ subtype: side$1 === "insertion" ? "table-insert" : "table-delete",
133059
+ tableFrom,
133060
+ tableTo,
133061
+ tablePos,
133062
+ wholeTable: true,
133063
+ decidable: true,
133064
+ rows: trackedRows.map((r) => r.ref),
133065
+ author: stringOf(primary$1.author),
133066
+ authorEmail: stringOf(primary$1.authorEmail),
133067
+ authorImage: stringOf(primary$1.authorImage),
133068
+ date: stringOf(primary$1.date),
133069
+ importedAuthor: stringOf(primary$1.importedAuthor),
133070
+ sourceId: stringOf(primary$1.sourceId),
133071
+ revisionGroupId: stringOf(primary$1.revisionGroupId) || representativeRevisionId$1 || publicId
133072
+ });
133073
+ return;
133074
+ }
133075
+ const side = trackedRows[0].side;
133076
+ const primary = trackedRows[0].tc;
133077
+ const representativeRevisionId = stringOf(primary.id) || stringOf(primary.sourceId);
133078
+ const reason = !everyRowTracked ? "partial-rows" : "mixed-sides";
133079
+ out.push({
133080
+ id: stringOf(primary.sourceId) || representativeRevisionId || `table:${tableFrom}:${side}`,
133081
+ revisionId: representativeRevisionId,
133082
+ side,
133083
+ subtype: side === "insertion" ? "table-insert" : "table-delete",
133084
+ tableFrom,
133085
+ tableTo,
133086
+ tablePos,
133087
+ wholeTable: false,
133088
+ decidable: false,
133089
+ undecidableReason: reason,
133090
+ rows: trackedRows.map((r) => r.ref),
133091
+ author: stringOf(primary.author),
133092
+ authorEmail: stringOf(primary.authorEmail),
133093
+ authorImage: stringOf(primary.authorImage),
133094
+ date: stringOf(primary.date),
133095
+ importedAuthor: stringOf(primary.importedAuthor),
133096
+ sourceId: stringOf(primary.sourceId),
133097
+ revisionGroupId: stringOf(primary.revisionGroupId) || representativeRevisionId
133098
+ });
133099
+ }, stringOf = (value) => typeof value === "string" ? value : value == null ? "" : String(value), groupedCache, SDT_NODE_NAMES, SDT_BLOCK_NAME = "structuredContentBlock", SDT_INLINE_NAME = "structuredContent", SDT_NODE_TYPES, VALID_CONTROL_TYPES, VALID_LOCK_MODES2, VALID_APPEARANCES, FIELD_LIKE_SDT_TYPES, liveDocumentCountsCache, BIBLIOGRAPHY_NAMESPACE_URI = "http://schemas.openxmlformats.org/officeDocument/2006/bibliography", CUSTOM_XML_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml", CUSTOM_XML_PROPS_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps", DEFAULT_SELECTED_STYLE = "/APA.XSL", DEFAULT_STYLE_NAME = "APA", DEFAULT_VERSION = "6", API_TO_OOXML_SOURCE_TYPE, OOXML_TO_API_SOURCE_TYPE, SIMPLE_FIELD_TO_XML_TAG, XML_TAG_TO_SIMPLE_FIELD, import_lib2, FONT_FAMILY_FALLBACKS, DEFAULT_GENERIC_FALLBACK = "sans-serif", DEFAULT_FONT_SIZE_PT = 10, CURRENT_APP_VERSION = "1.38.0", SUPERDOC_DOCUMENT_ORIGIN_PROPERTY = "SuperdocDocumentOrigin", STORED_DOCUMENT_ORIGINS, collectRunDefaultProperties = (runProps, { allowOverrideTypeface = true, allowOverrideSize = true, themeResolver, state }) => {
132723
133100
  if (!runProps?.elements?.length || !state)
132724
133101
  return;
132725
133102
  const fontsNode = runProps.elements.find((el) => el.name === "w:rFonts");
@@ -132753,7 +133130,7 @@ var isRegExp = (value) => {
132753
133130
  state.kern = kernNode.attributes["w:val"];
132754
133131
  }
132755
133132
  }, SuperConverter;
132756
- var init_SuperConverter_D2zNnC50_es = __esm(() => {
133133
+ var init_SuperConverter_BBjNvGFh_es = __esm(() => {
132757
133134
  init_rolldown_runtime_Bg48TavK_es();
132758
133135
  init_jszip_C49i9kUs_es();
132759
133136
  init_xml_js_CqGKpaft_es();
@@ -137769,7 +138146,7 @@ var init_SuperConverter_D2zNnC50_es = __esm(() => {
137769
138146
  "trackChanges.list": {
137770
138147
  memberPath: "trackChanges.list",
137771
138148
  description: "List all tracked changes in the document.",
137772
- expectedResult: "Returns a TrackChangesListResult with tracked change entries (`insert`, `delete`, `replacement`, `format`), total count, and raw imported Word OOXML revision IDs (`w:id`) when available.",
138149
+ expectedResult: "Returns a TrackChangesListResult with tracked change entries (`insert`, `delete`, `replacement`, `format`, `structural`), total count, and raw imported Word OOXML revision IDs (`w:id`) when available. Structural changes (whole-table insert/delete) carry a `subtype` of `table-insert` or `table-delete`.",
137773
138150
  requiresDocumentContext: true,
137774
138151
  metadata: readOperation2({
137775
138152
  idempotency: "idempotent",
@@ -137783,7 +138160,7 @@ var init_SuperConverter_D2zNnC50_es = __esm(() => {
137783
138160
  "trackChanges.get": {
137784
138161
  memberPath: "trackChanges.get",
137785
138162
  description: "Retrieve a single tracked change by ID.",
137786
- expectedResult: "Returns a TrackChangeInfo object with the change type (`insert`, `delete`, `replacement`, `format`), author, date, affected content, and raw imported Word OOXML revision IDs (`w:id`) when available.",
138163
+ expectedResult: "Returns a TrackChangeInfo object with the change type (`insert`, `delete`, `replacement`, `format`, `structural`), author, date, affected content, and raw imported Word OOXML revision IDs (`w:id`) when available. Structural changes (whole-table insert/delete) carry a `subtype` of `table-insert` or `table-delete`.",
137787
138164
  requiresDocumentContext: true,
137788
138165
  metadata: readOperation2({
137789
138166
  idempotency: "idempotent",
@@ -142282,7 +142659,8 @@ var init_SuperConverter_D2zNnC50_es = __esm(() => {
142282
142659
  "insert",
142283
142660
  "delete",
142284
142661
  "replacement",
142285
- "format"
142662
+ "format",
142663
+ "structural"
142286
142664
  ];
142287
142665
  nodeTypeValues2 = NODE_TYPES2;
142288
142666
  blockNodeTypeValues2 = BLOCK_NODE_TYPES2;
@@ -143312,6 +143690,10 @@ var init_SuperConverter_D2zNnC50_es = __esm(() => {
143312
143690
  address: trackedChangeAddressSchema2,
143313
143691
  id: { type: "string" },
143314
143692
  type: { enum: [...trackChangeTypeValues2] },
143693
+ subtype: {
143694
+ enum: ["table-insert", "table-delete"],
143695
+ description: "Finer classification for structural changes (type === 'structural')."
143696
+ },
143315
143697
  grouping: { enum: [
143316
143698
  "standalone",
143317
143699
  "replacement-pair",
@@ -143334,6 +143716,10 @@ var init_SuperConverter_D2zNnC50_es = __esm(() => {
143334
143716
  discoveryResultSchema2(discoveryItemSchema2({
143335
143717
  address: trackedChangeAddressSchema2,
143336
143718
  type: { enum: [...trackChangeTypeValues2] },
143719
+ subtype: {
143720
+ enum: ["table-insert", "table-delete"],
143721
+ description: "Finer classification for structural changes (type === 'structural')."
143722
+ },
143337
143723
  grouping: { enum: [
143338
143724
  "standalone",
143339
143725
  "replacement-pair",
@@ -145828,7 +146214,7 @@ var init_SuperConverter_D2zNnC50_es = __esm(() => {
145828
146214
  },
145829
146215
  type: {
145830
146216
  enum: [...trackChangeTypeValues2],
145831
- description: "Filter by change type: 'insert', 'delete', 'replacement', or 'format'."
146217
+ description: "Filter by change type: 'insert', 'delete', 'replacement', 'format', or 'structural'."
145832
146218
  },
145833
146219
  in: {
145834
146220
  oneOf: [storyLocatorSchema2, { const: "all" }],
@@ -145839,7 +146225,11 @@ var init_SuperConverter_D2zNnC50_es = __esm(() => {
145839
146225
  story: storyLocatorSchema2
145840
146226
  }, ["id"]), objectSchema2({
145841
146227
  id: { type: "string" },
145842
- story: storyLocatorSchema2
146228
+ story: storyLocatorSchema2,
146229
+ range: {
146230
+ type: "object",
146231
+ description: "Partial-range qualifier on an id target. Rejected with INVALID_INPUT for indivisible (e.g. structural) revisions."
146232
+ }
145843
146233
  }, ["id"]), objectSchema2({
145844
146234
  kind: { const: "range" },
145845
146235
  range: textTargetSchema2,
@@ -171800,7 +172190,7 @@ var init_SuperConverter_D2zNnC50_es = __esm(() => {
171800
172190
  };
171801
172191
  });
171802
172192
 
171803
- // ../../packages/superdoc/dist/chunks/create-headless-toolbar-COmoIa5Q.es.js
172193
+ // ../../packages/superdoc/dist/chunks/create-headless-toolbar-s_kl3MP8.es.js
171804
172194
  function parseSizeUnit(val = "0") {
171805
172195
  const length3 = val.toString() || "0";
171806
172196
  const value = Number.parseFloat(length3);
@@ -182133,8 +182523,8 @@ var CSS_DIMENSION_REGEX, DOM_SIZE_UNITS, normalizeActorId = (value) => {
182133
182523
  }
182134
182524
  };
182135
182525
  };
182136
- var init_create_headless_toolbar_COmoIa5Q_es = __esm(() => {
182137
- init_SuperConverter_D2zNnC50_es();
182526
+ var init_create_headless_toolbar_s_kl3MP8_es = __esm(() => {
182527
+ init_SuperConverter_BBjNvGFh_es();
182138
182528
  init_uuid_qzgm05fK_es();
182139
182529
  init_constants_D9qj59G2_es();
182140
182530
  init_dist_B8HfvhaK_es();
@@ -231297,7 +231687,7 @@ var init_remark_gfm_eZN6yzWQ_es = __esm(() => {
231297
231687
  init_remark_gfm_BhnWr3yf_es();
231298
231688
  });
231299
231689
 
231300
- // ../../packages/superdoc/dist/chunks/src-eTZqPcFn.es.js
231690
+ // ../../packages/superdoc/dist/chunks/src-DeS9kJS7.es.js
231301
231691
  function deleteProps(obj, propOrProps) {
231302
231692
  const props = typeof propOrProps === "string" ? [propOrProps] : propOrProps;
231303
231693
  const removeNested = (target, pathParts, index2 = 0) => {
@@ -248098,6 +248488,7 @@ function buildProjectedInfo(snapshot2, options = {}) {
248098
248488
  },
248099
248489
  id: id2,
248100
248490
  type,
248491
+ ...type === "structural" && snapshot2.subtype ? { subtype: snapshot2.subtype } : {},
248101
248492
  grouping: options.grouping,
248102
248493
  pairedWithChangeId: options.pairedWithChangeId ?? undefined,
248103
248494
  wordRevisionIds: normalizeWordRevisionIds(snapshot2.wordRevisionIds),
@@ -248353,10 +248744,11 @@ function trackChangesListWrapper(editor, input2) {
248353
248744
  const items = paged.items.map((row2) => {
248354
248745
  const info = row2.info;
248355
248746
  const handle3 = buildResolvedHandle(row2.handleKey, "stable", "trackedChange");
248356
- const { address: address2, type, grouping, pairedWithChangeId, wordRevisionIds, overlap, author, authorEmail, authorImage, date, excerpt, insertedText, deletedText, origin, imported } = info;
248747
+ const { address: address2, type, subtype, grouping, pairedWithChangeId, wordRevisionIds, overlap, author, authorEmail, authorImage, date, excerpt, insertedText, deletedText, origin, imported } = info;
248357
248748
  return buildDiscoveryItem(info.id, handle3, {
248358
248749
  address: address2,
248359
248750
  type,
248751
+ ...subtype ? { subtype } : {},
248360
248752
  grouping,
248361
248753
  pairedWithChangeId,
248362
248754
  wordRevisionIds,
@@ -248419,6 +248811,7 @@ function trackChangesGetWrapper(editor, input2) {
248419
248811
  },
248420
248812
  id: resolved.change.id,
248421
248813
  type,
248814
+ ...type === "structural" && resolved.change.structural ? { subtype: resolved.change.structural.subtype } : {},
248422
248815
  grouping,
248423
248816
  wordRevisionIds: normalizeWordRevisionIds(resolved.change.wordRevisionIds),
248424
248817
  overlap: resolved.change.overlap,
@@ -293641,7 +294034,8 @@ var Node$13 = class Node$14 {
293641
294034
  if (!meta2) {
293642
294035
  let mightAffectTrackChanges = false;
293643
294036
  tr.steps.forEach((step3) => {
293644
- if (step3.slice || step3.from !== step3.to)
294037
+ const replaceStep$2 = step3;
294038
+ if (replaceStep$2.slice || replaceStep$2.from !== replaceStep$2.to)
293645
294039
  mightAffectTrackChanges = true;
293646
294040
  });
293647
294041
  if (mightAffectTrackChanges)
@@ -293672,8 +294066,9 @@ var Node$13 = class Node$14 {
293672
294066
  return DecorationSet.empty;
293673
294067
  const decorations = [];
293674
294068
  const trackedChanges = getTrackChanges(state);
294069
+ addStructuralRowDecorations(decorations, state, onlyOriginalShown, onlyModifiedShown);
293675
294070
  if (!trackedChanges.length)
293676
- return DecorationSet.empty;
294071
+ return decorations.length ? DecorationSet.create(state.doc, decorations) : DecorationSet.empty;
293677
294072
  trackedChanges.forEach(({ mark: mark2, from: from$1, to }) => {
293678
294073
  if (mark2.type.name === "trackInsert")
293679
294074
  if (onlyOriginalShown) {
@@ -293719,6 +294114,27 @@ var Node$13 = class Node$14 {
293719
294114
  }
293720
294115
  });
293721
294116
  return DecorationSet.create(state.doc, decorations);
294117
+ }, addStructuralRowDecorations = (decorations, state, onlyOriginalShown, onlyModifiedShown) => {
294118
+ const structuralChanges = enumerateStructuralRowChanges(state);
294119
+ if (!structuralChanges.length)
294120
+ return;
294121
+ for (const change of structuralChanges) {
294122
+ const isInsert = change.side === "insertion";
294123
+ const baseClass = isInsert ? "track-row-insert-dec" : "track-row-delete-dec";
294124
+ let mode = "highlighted";
294125
+ if (onlyOriginalShown)
294126
+ mode = isInsert ? "hidden" : "normal";
294127
+ else if (onlyModifiedShown)
294128
+ mode = isInsert ? "normal" : "hidden";
294129
+ for (const row2 of change.rows)
294130
+ decorations.push(Decoration.node(row2.from, row2.to, {
294131
+ class: `${baseClass} ${mode}`,
294132
+ "data-track-change-id": change.id,
294133
+ "data-track-change-kind": change.subtype,
294134
+ "data-track-change-author": change.author || "",
294135
+ "data-track-change-date": change.date || ""
294136
+ }));
294137
+ }
293722
294138
  }, resolveCommentMeta = ({ converter, importedId }) => {
293723
294139
  const matchingImportedComment = (converter?.comments || []).find((c) => c.importedId == importedId);
293724
294140
  const resolvedCommentId = matchingImportedComment?.commentId ?? (importedId ? String(importedId) : v4_default());
@@ -299711,11 +300127,12 @@ var Node$13 = class Node$14 {
299711
300127
  }, BODY_STORY, buildReviewGraph = ({ state, story = BODY_STORY, replacementsMode = "paired" }) => {
299712
300128
  return buildGraphFromSpans({
299713
300129
  spans: enumerateTrackedMarkSpans(state),
300130
+ structuralChanges: enumerateStructuralRowChanges(state),
299714
300131
  doc: state?.doc ?? null,
299715
300132
  story,
299716
300133
  replacementsMode
299717
300134
  });
299718
- }, buildGraphFromSpans = ({ spans, doc: doc$12, story, replacementsMode }) => {
300135
+ }, buildGraphFromSpans = ({ spans, structuralChanges = [], doc: doc$12, story, replacementsMode }) => {
299719
300136
  const mergedSegments = mergeAdjacentSpans(spans.map((span) => ({
299720
300137
  attrs: readTrackedAttrs(span.mark, span.mark.type.name),
299721
300138
  span
@@ -299774,7 +300191,26 @@ var Node$13 = class Node$14 {
299774
300191
  for (const segs of segmentsByChangeId.values())
299775
300192
  for (const seg of segs)
299776
300193
  bySegmentId.set(seg.segmentId, seg);
299777
- const segments = mergedSegments;
300194
+ for (const structural of structuralChanges) {
300195
+ const logical = buildStructuralLogicalChange({
300196
+ structural,
300197
+ doc: doc$12,
300198
+ story
300199
+ });
300200
+ if (!logical)
300201
+ continue;
300202
+ const internalKey = `structural:${structural.tablePos}:${structural.side}`;
300203
+ if (changes.has(internalKey))
300204
+ continue;
300205
+ changes.set(internalKey, logical);
300206
+ if (logical.id && logical.id !== internalKey && !changes.has(logical.id))
300207
+ changes.set(logical.id, logical);
300208
+ for (const seg of logical.segments)
300209
+ bySegmentId.set(seg.segmentId, seg);
300210
+ mergedSegments.push(...logical.segments);
300211
+ appendToMap(byRevisionGroupId, logical.revisionGroupId, logical.id);
300212
+ }
300213
+ const segments = mergedSegments.slice().sort((a2, b$1) => a2.from - b$1.from || a2.to - b$1.to);
299778
300214
  const graph = {
299779
300215
  changes,
299780
300216
  segments,
@@ -299938,6 +300374,90 @@ var Node$13 = class Node$14 {
299938
300374
  enumerable: false
299939
300375
  });
299940
300376
  return logical;
300377
+ }, buildStructuralLogicalChange = ({ structural, doc: doc$12, story }) => {
300378
+ const side = structural.side === "insertion" ? SegmentSide.Inserted : SegmentSide.Deleted;
300379
+ const from$1 = structural.tableFrom;
300380
+ const to = structural.tableTo;
300381
+ if (!(from$1 < to))
300382
+ return null;
300383
+ const attrs = {
300384
+ id: structural.id,
300385
+ revisionGroupId: structural.revisionGroupId,
300386
+ splitFromId: "",
300387
+ changeType: CanonicalChangeType.Structural,
300388
+ replacementGroupId: "",
300389
+ replacementSideId: "",
300390
+ overlapParentId: "",
300391
+ sourceIds: structural.sourceId ? { wordIdStructural: structural.sourceId } : {},
300392
+ sourceId: structural.sourceId,
300393
+ importedAuthor: structural.importedAuthor,
300394
+ origin: structural.sourceId ? "word" : "",
300395
+ author: structural.author,
300396
+ authorId: "",
300397
+ authorEmail: structural.authorEmail,
300398
+ authorImage: structural.authorImage,
300399
+ date: structural.date,
300400
+ markType: "",
300401
+ side,
300402
+ subtype: structural.subtype,
300403
+ explicitChangeType: CanonicalChangeType.Structural,
300404
+ hasReviewMetadata: true
300405
+ };
300406
+ const segment = {
300407
+ segmentId: `${structural.id}:structural:${from$1}:${to}:0`,
300408
+ changeId: structural.id,
300409
+ markType: "",
300410
+ side,
300411
+ from: from$1,
300412
+ to,
300413
+ text: "",
300414
+ mark: null,
300415
+ markRuns: [],
300416
+ attrs,
300417
+ parentId: "",
300418
+ parentSide: "",
300419
+ overlapRole: "standalone",
300420
+ structural: true
300421
+ };
300422
+ if (doc$12)
300423
+ try {
300424
+ segment.text = doc$12.textBetween(from$1, to, " ", "");
300425
+ } catch {
300426
+ segment.text = "";
300427
+ }
300428
+ const segments = [segment];
300429
+ const logical = {
300430
+ id: structural.id,
300431
+ type: CanonicalChangeType.Structural,
300432
+ subtype: structural.subtype,
300433
+ state: "open",
300434
+ segments,
300435
+ coverageSegments: [...segments],
300436
+ insertedSegments: side === SegmentSide.Inserted ? [...segments] : [],
300437
+ deletedSegments: side === SegmentSide.Deleted ? [...segments] : [],
300438
+ formattingSegments: [],
300439
+ replacement: null,
300440
+ author: structural.author,
300441
+ authorId: "",
300442
+ authorEmail: structural.authorEmail,
300443
+ authorImage: structural.authorImage,
300444
+ date: structural.date,
300445
+ sourceIds: attrs.sourceIds,
300446
+ revisionGroupId: structural.revisionGroupId,
300447
+ splitFromId: "",
300448
+ sourcePlatform: structural.sourceId ? "word" : "",
300449
+ story,
300450
+ parent: null,
300451
+ children: [],
300452
+ before: [],
300453
+ after: [],
300454
+ excerpt: segment.text.length > 200 ? `${segment.text.slice(0, 200)}…` : segment.text
300455
+ };
300456
+ Object.defineProperty(logical, "structural", {
300457
+ value: structural,
300458
+ enumerable: false
300459
+ });
300460
+ return logical;
299941
300461
  }, aggregateSourceIds = (segments) => {
299942
300462
  const out = {};
299943
300463
  const sorted = [...segments].sort((a2, b$1) => {
@@ -301378,7 +301898,170 @@ var Node$13 = class Node$14 {
301378
301898
  date,
301379
301899
  source
301380
301900
  };
301381
- }, findDocPosByTextOffset = ({ doc: doc$12, from: from$1, to, textOffset }) => {
301901
+ }, collectWholeTablesInRange = ({ doc: doc$12, from: from$1, to }) => {
301902
+ if (!doc$12 || typeof from$1 !== "number" || typeof to !== "number" || to <= from$1)
301903
+ return [];
301904
+ const boundedFrom = Math.max(0, from$1);
301905
+ const boundedTo = Math.min(doc$12.content.size, to);
301906
+ if (boundedTo <= boundedFrom)
301907
+ return [];
301908
+ const tables = [];
301909
+ doc$12.nodesBetween(boundedFrom, boundedTo, (node3, pos) => {
301910
+ if (node3.type?.name !== "table")
301911
+ return true;
301912
+ if (pos >= boundedFrom && pos + node3.nodeSize <= boundedTo) {
301913
+ tables.push({
301914
+ pos,
301915
+ node: node3,
301916
+ from: pos,
301917
+ to: pos + node3.nodeSize
301918
+ });
301919
+ return false;
301920
+ }
301921
+ return true;
301922
+ });
301923
+ return tables;
301924
+ }, stampTableRows = ({ type, tr, from: from$1, to, user, date }) => {
301925
+ if (type !== "rowInsert" && type !== "rowDelete")
301926
+ return false;
301927
+ const tables = collectWholeTablesInRange({
301928
+ doc: tr.doc,
301929
+ from: from$1,
301930
+ to
301931
+ });
301932
+ if (!tables.length)
301933
+ return false;
301934
+ let stamped = false;
301935
+ for (const { pos: tablePos, node: tableNode } of tables) {
301936
+ const revisionGroupId = v4_default();
301937
+ let offset$1 = 1;
301938
+ const rowPositions = [];
301939
+ tableNode.forEach((child) => {
301940
+ const childPos = tablePos + offset$1;
301941
+ offset$1 += child.nodeSize;
301942
+ if (child.type?.name === "tableRow")
301943
+ rowPositions.push(childPos);
301944
+ });
301945
+ for (const rowPos of rowPositions) {
301946
+ const rowNode = tr.doc.nodeAt(rowPos);
301947
+ if (!rowNode || rowNode.type?.name !== "tableRow")
301948
+ continue;
301949
+ if (rowNode.attrs?.trackChange)
301950
+ continue;
301951
+ const trackChange = {
301952
+ type,
301953
+ id: v4_default(),
301954
+ author: user?.name || "",
301955
+ authorId: user?.id || "",
301956
+ authorEmail: user?.email || "",
301957
+ authorImage: user?.image || "",
301958
+ date,
301959
+ revisionGroupId
301960
+ };
301961
+ tr.setNodeMarkup(rowPos, undefined, {
301962
+ ...rowNode.attrs,
301963
+ trackChange
301964
+ });
301965
+ stamped = true;
301966
+ }
301967
+ }
301968
+ return stamped;
301969
+ }, markDeletion = ({ tr, from: from$1, to, user, date, id: providedId }) => {
301970
+ const currentIdentity = getCurrentUserIdentity({ options: { user } });
301971
+ const isOwnInsertion = (mark2) => {
301972
+ const changeIdentity = getChangeAuthorIdentity(mark2);
301973
+ if (matchesSameUserRefinement({
301974
+ currentUser: currentIdentity,
301975
+ change: changeIdentity
301976
+ }))
301977
+ return true;
301978
+ if (!changeIdentity.hasId && !changeIdentity.hasEmail)
301979
+ return shouldCollapseNoEmailInsertion({
301980
+ currentUser: user,
301981
+ insertionAttrs: mark2?.attrs
301982
+ });
301983
+ return false;
301984
+ };
301985
+ const trackedMark = findTrackedMarkBetween({
301986
+ tr,
301987
+ from: from$1,
301988
+ to,
301989
+ markName: TrackDeleteMarkName,
301990
+ predicate: (mark2) => matchesSameUserRefinement({
301991
+ currentUser: currentIdentity,
301992
+ change: getChangeAuthorIdentity(mark2)
301993
+ })
301994
+ });
301995
+ let id2;
301996
+ if (providedId)
301997
+ id2 = providedId;
301998
+ else if (trackedMark)
301999
+ id2 = trackedMark.mark.attrs.id;
302000
+ else
302001
+ id2 = v4_default();
302002
+ const deletionMark = tr.doc.type.schema.marks[TrackDeleteMarkName].create({
302003
+ id: id2,
302004
+ author: user.name || "",
302005
+ authorId: user.id || "",
302006
+ authorEmail: user.email || "",
302007
+ authorImage: user.image || "",
302008
+ date
302009
+ });
302010
+ const deletionMap = new Mapping;
302011
+ const shouldReassignExistingDeletions = Boolean(providedId);
302012
+ let nodes = [];
302013
+ tr.doc.nodesBetween(from$1, to, (node3, pos) => {
302014
+ if (node3.type.name.includes("table"))
302015
+ return;
302016
+ if (!node3.isInline || !node3.isLeaf)
302017
+ return;
302018
+ const mappedFrom = deletionMap.map(Math.max(from$1, pos));
302019
+ const mappedTo = deletionMap.map(Math.min(to, pos + node3.nodeSize));
302020
+ if (mappedFrom >= mappedTo)
302021
+ return;
302022
+ const insertMark = node3.marks.find((mark2) => mark2.type.name === TrackInsertMarkName);
302023
+ const existingDeleteMarks = node3.marks.filter((mark2) => mark2.type.name === TrackDeleteMarkName);
302024
+ if (insertMark && isOwnInsertion(insertMark)) {
302025
+ const removeStep = new ReplaceStep(mappedFrom, mappedTo, Slice.empty);
302026
+ if (!tr.maybeStep(removeStep).failed)
302027
+ deletionMap.appendMap(removeStep.getMap());
302028
+ return;
302029
+ }
302030
+ if (existingDeleteMarks.length > 0) {
302031
+ if (shouldReassignExistingDeletions) {
302032
+ nodes.push(node3);
302033
+ existingDeleteMarks.forEach((existingDeleteMark) => {
302034
+ tr.removeMark(mappedFrom, mappedTo, existingDeleteMark);
302035
+ });
302036
+ tr.addMark(mappedFrom, mappedTo, deletionMark);
302037
+ }
302038
+ return;
302039
+ }
302040
+ nodes.push(node3);
302041
+ tr.addMark(mappedFrom, mappedTo, deletionMark);
302042
+ });
302043
+ return {
302044
+ deletionMark,
302045
+ deletionMap,
302046
+ nodes
302047
+ };
302048
+ }, sliceContainsTable = (slice2) => {
302049
+ const content3 = slice2?.content;
302050
+ if (!content3)
302051
+ return false;
302052
+ let found2 = false;
302053
+ content3.forEach((node3) => {
302054
+ if (found2)
302055
+ return;
302056
+ if (node3?.type?.name === "table")
302057
+ found2 = true;
302058
+ });
302059
+ return found2;
302060
+ }, rangeContainsWholeTable = ({ doc: doc$12, from: from$1, to }) => collectWholeTablesInRange({
302061
+ doc: doc$12,
302062
+ from: from$1,
302063
+ to
302064
+ }).length > 0, findDocPosByTextOffset = ({ doc: doc$12, from: from$1, to, textOffset }) => {
301382
302065
  let remaining = textOffset;
301383
302066
  let foundPos = null;
301384
302067
  doc$12.nodesBetween(from$1, to, (node3, pos) => {
@@ -301487,7 +302170,139 @@ var Node$13 = class Node$14 {
301487
302170
  return;
301488
302171
  }
301489
302172
  }
302173
+ }, tryStructuralTableInsert = ({ newTr, step: step3, map: map$12, user, date }) => {
302174
+ const beforeSteps = newTr.steps.length;
302175
+ const beforeSize = newTr.doc.content.size;
302176
+ const insertAt = step3.from;
302177
+ const replacedLength = step3.to - step3.from;
302178
+ if (step3.from !== step3.to) {
302179
+ let hasRealContent = false;
302180
+ newTr.doc.nodesBetween(step3.from, step3.to, (node3) => {
302181
+ if (hasRealContent)
302182
+ return false;
302183
+ if (node3.isText && node3.text || node3.isLeaf && !node3.isText)
302184
+ hasRealContent = true;
302185
+ return !hasRealContent;
302186
+ });
302187
+ if (hasRealContent)
302188
+ return { handled: false };
302189
+ }
302190
+ if (newTr.maybeStep(step3).failed)
302191
+ return { handled: false };
302192
+ const stepMap = newTr.steps[beforeSteps].getMap();
302193
+ map$12.appendMap(stepMap);
302194
+ const insertedFrom = insertAt;
302195
+ const insertedTo = insertAt + (newTr.doc.content.size - beforeSize) + replacedLength;
302196
+ if (insertedTo > insertedFrom) {
302197
+ let hasInlineText = false;
302198
+ newTr.doc.nodesBetween(insertedFrom, insertedTo, (node3) => {
302199
+ if (node3.isText && node3.text) {
302200
+ hasInlineText = true;
302201
+ return false;
302202
+ }
302203
+ });
302204
+ if (hasInlineText)
302205
+ markInsertion({
302206
+ tr: newTr,
302207
+ from: insertedFrom,
302208
+ to: insertedTo,
302209
+ user,
302210
+ date
302211
+ });
302212
+ }
302213
+ stampTableRows({
302214
+ type: "rowInsert",
302215
+ tr: newTr,
302216
+ from: insertedFrom,
302217
+ to: insertedTo,
302218
+ user,
302219
+ date
302220
+ });
302221
+ newTr.setMeta(TrackChangesBasePluginKey, { insertedTo });
302222
+ newTr.setMeta(CommentsPluginKey, { type: "force" });
302223
+ return { handled: true };
302224
+ }, tryStructuralTableDelete = ({ newTr, step: step3, map: map$12, originalStep, originalStepIndex, tr, user, date }) => {
302225
+ const from$1 = step3.from;
302226
+ const to = step3.to;
302227
+ const tableRanges = collectWholeTablesInRange({
302228
+ doc: newTr.doc,
302229
+ from: from$1,
302230
+ to
302231
+ });
302232
+ let hasOutsideText = false;
302233
+ newTr.doc.nodesBetween(from$1, to, (node3, pos) => {
302234
+ if (hasOutsideText)
302235
+ return false;
302236
+ if (node3.isText && node3.text && !tableRanges.some((r$1) => pos >= r$1.from && pos < r$1.to)) {
302237
+ hasOutsideText = true;
302238
+ return false;
302239
+ }
302240
+ });
302241
+ if (hasOutsideText)
302242
+ return { handled: false };
302243
+ let hasInlineText = false;
302244
+ newTr.doc.nodesBetween(from$1, to, (node3) => {
302245
+ if (node3.isText && node3.text) {
302246
+ hasInlineText = true;
302247
+ return false;
302248
+ }
302249
+ });
302250
+ if (hasInlineText)
302251
+ markDeletion({
302252
+ tr: newTr,
302253
+ from: from$1,
302254
+ to,
302255
+ user,
302256
+ date
302257
+ });
302258
+ if (!stampTableRows({
302259
+ type: "rowDelete",
302260
+ tr: newTr,
302261
+ from: from$1,
302262
+ to,
302263
+ user,
302264
+ date
302265
+ }) && !hasInlineText)
302266
+ return { handled: false };
302267
+ if (map$12 && originalStep && tr)
302268
+ try {
302269
+ const invertStep = originalStep.invert(tr.docs[originalStepIndex]).map(map$12);
302270
+ if (invertStep)
302271
+ map$12.appendMap(invertStep.getMap());
302272
+ } catch {}
302273
+ newTr.setMeta(TrackChangesBasePluginKey, {});
302274
+ newTr.setMeta(CommentsPluginKey, { type: "force" });
302275
+ return { handled: true };
301490
302276
  }, tryCompileStep = ({ state, tr, newTr, step: step3, stepWasNormalized, originalStep, originalStepIndex, map: map$12, user, date, replacements }) => {
302277
+ if (step3.slice.content.size > 0 && sliceContainsTable(step3.slice)) {
302278
+ const structural = tryStructuralTableInsert({
302279
+ newTr,
302280
+ step: step3,
302281
+ map: map$12,
302282
+ user,
302283
+ date
302284
+ });
302285
+ if (structural.handled)
302286
+ return structural;
302287
+ }
302288
+ if (step3.from !== step3.to && step3.slice.content.size === 0 && rangeContainsWholeTable({
302289
+ doc: newTr.doc,
302290
+ from: step3.from,
302291
+ to: step3.to
302292
+ })) {
302293
+ const structural = tryStructuralTableDelete({
302294
+ newTr,
302295
+ step: step3,
302296
+ map: map$12,
302297
+ originalStep,
302298
+ originalStepIndex,
302299
+ tr,
302300
+ user,
302301
+ date
302302
+ });
302303
+ if (structural.handled)
302304
+ return structural;
302305
+ }
301491
302306
  if (step3.from !== step3.to && step3.slice.content.size === 0) {
301492
302307
  let hasInlineContent = false;
301493
302308
  newTr.doc.nodesBetween(step3.from, step3.to, (node3) => {
@@ -301591,6 +302406,15 @@ var Node$13 = class Node$14 {
301591
302406
  meta2.selectionPos = result.selection.pos;
301592
302407
  newTr.setMeta(TrackChangesBasePluginKey, meta2);
301593
302408
  newTr.setMeta(CommentsPluginKey, { type: "force" });
302409
+ if (typeof result.insertedTo === "number" && result.insertedTo > step3.from)
302410
+ stampTableRows({
302411
+ type: "rowInsert",
302412
+ tr: newTr,
302413
+ from: step3.from,
302414
+ to: result.insertedTo,
302415
+ user,
302416
+ date
302417
+ });
301594
302418
  return {
301595
302419
  handled: true,
301596
302420
  sizeDelta: newTr.doc.content.size - beforeSize
@@ -302314,8 +303138,7 @@ var Node$13 = class Node$14 {
302314
303138
  state,
302315
303139
  graph,
302316
303140
  selections,
302317
- decision,
302318
- replacements
303141
+ decision
302319
303142
  });
302320
303143
  if (!planResult.ok)
302321
303144
  return planResult.failure;
@@ -302410,10 +303233,20 @@ var Node$13 = class Node$14 {
302410
303233
  ok: false,
302411
303234
  failure: failure$3("INVALID_TARGET", "decision target shape was not recognised.")
302412
303235
  };
303236
+ }, resolveLogicalChangeById = (graph, id2) => {
303237
+ const key2 = String(id2);
303238
+ for (const candidate of graph.changes.values())
303239
+ if (candidate?.type === CanonicalChangeType.Structural && String(candidate.id) === key2)
303240
+ return candidate;
303241
+ return graph.changes.get(id2);
302413
303242
  }, resolveTargetToSelections = ({ graph, normalized }) => {
302414
303243
  if (normalized.kind === "all") {
302415
303244
  const sel = [];
302416
- for (const change of graph.changes.values())
303245
+ const seen = /* @__PURE__ */ new Set;
303246
+ for (const change of graph.changes.values()) {
303247
+ if (seen.has(change))
303248
+ continue;
303249
+ seen.add(change);
302417
303250
  sel.push({
302418
303251
  change,
302419
303252
  coverage: "full",
@@ -302422,6 +303255,7 @@ var Node$13 = class Node$14 {
302422
303255
  to: s2.to
302423
303256
  }))
302424
303257
  });
303258
+ }
302425
303259
  sel.sort((a2, b$1) => firstFrom(a2) - firstFrom(b$1));
302426
303260
  return {
302427
303261
  ok: true,
@@ -302429,7 +303263,7 @@ var Node$13 = class Node$14 {
302429
303263
  };
302430
303264
  }
302431
303265
  if (normalized.kind === "id") {
302432
- const change = graph.changes.get(normalized.id);
303266
+ const change = resolveLogicalChangeById(graph, normalized.id);
302433
303267
  if (!change)
302434
303268
  return {
302435
303269
  ok: false,
@@ -302454,7 +303288,7 @@ var Node$13 = class Node$14 {
302454
303288
  const overlapTo = Math.min(segment.to, to);
302455
303289
  if (overlapFrom >= overlapTo) {
302456
303290
  if (from$1 === to && segment.from <= from$1 && segment.to > from$1) {
302457
- const change$1 = graph.changes.get(segment.changeId);
303291
+ const change$1 = resolveLogicalChangeById(graph, segment.changeId);
302458
303292
  if (!change$1)
302459
303293
  continue;
302460
303294
  const existing$1 = byId.get(change$1.id);
@@ -302476,7 +303310,7 @@ var Node$13 = class Node$14 {
302476
303310
  }
302477
303311
  continue;
302478
303312
  }
302479
- const change = graph.changes.get(segment.changeId);
303313
+ const change = resolveLogicalChangeById(graph, segment.changeId);
302480
303314
  if (!change)
302481
303315
  continue;
302482
303316
  const existing = byId.get(change.id);
@@ -302574,17 +303408,137 @@ var Node$13 = class Node$14 {
302574
303408
  };
302575
303409
  }
302576
303410
  return { ok: true };
302577
- }, buildMutationPlan = ({ state, graph, selections, decision, replacements }) => {
303411
+ }, buildMutationPlan = ({ state, graph, selections, decision }) => {
302578
303412
  const ops = [];
302579
303413
  const removedRanges = [];
302580
303414
  const resolvedRanges = [];
302581
303415
  const touched = /* @__PURE__ */ new Set;
302582
303416
  const retired = /* @__PURE__ */ new Set;
302583
303417
  const diagnostics = [];
303418
+ const structuralTableRemovals = [];
303419
+ for (const selection of selections) {
303420
+ const change = selection.change;
303421
+ if (change.type !== CanonicalChangeType.Structural)
303422
+ continue;
303423
+ const structural = change.structural;
303424
+ if (!structural || structural.wholeTable !== true || structural.decidable === false)
303425
+ continue;
303426
+ if (!(structural.side === "insertion" && decision === "reject" || structural.side === "deletion" && decision === "accept"))
303427
+ continue;
303428
+ structuralTableRemovals.push({
303429
+ from: structural.tableFrom,
303430
+ to: structural.tableTo,
303431
+ structuralId: change.id
303432
+ });
303433
+ }
303434
+ const suppressedInsideTable = /* @__PURE__ */ new Set;
303435
+ const isInsideRemovedTable = (change) => structuralTableRemovals.length > 0 && change.type !== CanonicalChangeType.Structural && change.segments.length > 0 && change.segments.every((seg) => structuralTableRemovals.some((range) => range.from <= seg.from && range.to >= seg.to));
303436
+ const structuralTableStays = [];
303437
+ for (const selection of selections) {
303438
+ const change = selection.change;
303439
+ if (change.type !== CanonicalChangeType.Structural)
303440
+ continue;
303441
+ const structural = change.structural;
303442
+ if (!structural || structural.wholeTable !== true || structural.decidable === false)
303443
+ continue;
303444
+ if (!(structural.side === "insertion" && decision === "accept" || structural.side === "deletion" && decision === "reject"))
303445
+ continue;
303446
+ structuralTableStays.push({
303447
+ from: structural.tableFrom,
303448
+ to: structural.tableTo,
303449
+ structuralId: change.id
303450
+ });
303451
+ }
303452
+ const isInsideStayingTable = (change) => structuralTableStays.length > 0 && change.type !== CanonicalChangeType.Structural && change.segments.length > 0 && change.segments.every((seg) => structuralTableStays.some((range) => range.from <= seg.from && range.to >= seg.to));
303453
+ const cascadedInsideStayingTable = /* @__PURE__ */ new Set;
303454
+ const planContainedInlineChild = (change) => {
303455
+ if (cascadedInsideStayingTable.has(change.id))
303456
+ return null;
303457
+ cascadedInsideStayingTable.add(change.id);
303458
+ touched.add(change.id);
303459
+ const fullSelection = {
303460
+ change,
303461
+ coverage: "full",
303462
+ ranges: change.segments.map((s2) => ({
303463
+ from: s2.from,
303464
+ to: s2.to
303465
+ }))
303466
+ };
303467
+ if (change.type === CanonicalChangeType.Insertion) {
303468
+ planInsertionDecision({
303469
+ ops,
303470
+ change,
303471
+ selection: fullSelection,
303472
+ decision,
303473
+ removedRanges,
303474
+ retired
303475
+ });
303476
+ return null;
303477
+ }
303478
+ if (change.type === CanonicalChangeType.Deletion) {
303479
+ planDeletionDecision({
303480
+ ops,
303481
+ change,
303482
+ selection: fullSelection,
303483
+ decision,
303484
+ removedRanges,
303485
+ retired
303486
+ });
303487
+ return null;
303488
+ }
303489
+ if (change.type === CanonicalChangeType.Replacement) {
303490
+ const repResult = planReplacementDecision({
303491
+ ops,
303492
+ graph,
303493
+ change,
303494
+ decision,
303495
+ removedRanges,
303496
+ retired
303497
+ });
303498
+ if (!repResult.ok)
303499
+ return repResult.failure;
303500
+ return null;
303501
+ }
303502
+ if (change.type === CanonicalChangeType.Formatting) {
303503
+ planFormattingDecision({
303504
+ ops,
303505
+ change,
303506
+ decision,
303507
+ retired
303508
+ });
303509
+ return null;
303510
+ }
303511
+ cascadedInsideStayingTable.delete(change.id);
303512
+ touched.delete(change.id);
303513
+ return null;
303514
+ };
302584
303515
  for (const selection of selections) {
302585
303516
  const { change } = selection;
303517
+ if (isInsideRemovedTable(change)) {
303518
+ retired.add(change.id);
303519
+ touched.add(change.id);
303520
+ suppressedInsideTable.add(change.id);
303521
+ continue;
303522
+ }
303523
+ if (isInsideStayingTable(change)) {
303524
+ const failureResult = planContainedInlineChild(change);
303525
+ if (failureResult)
303526
+ return {
303527
+ ok: false,
303528
+ failure: failureResult
303529
+ };
303530
+ continue;
303531
+ }
302586
303532
  const isFull = selection.coverage === "full";
302587
303533
  if (!isFull) {
303534
+ if (change.type === CanonicalChangeType.Structural)
303535
+ return {
303536
+ ok: false,
303537
+ failure: failure$3("INVALID_INPUT", "partial-range decisions are not valid on an indivisible structural revision.", { details: {
303538
+ changeId: change.id,
303539
+ subtype: change.subtype
303540
+ } })
303541
+ };
302588
303542
  if (change.type === CanonicalChangeType.Replacement)
302589
303543
  return {
302590
303544
  ok: false,
@@ -302604,7 +303558,20 @@ var Node$13 = class Node$14 {
302604
303558
  to: segment.to,
302605
303559
  cause: `${decision}:${change.id}`
302606
303560
  });
302607
- if (!isFull && (change.type === CanonicalChangeType.Insertion || change.type === CanonicalChangeType.Deletion)) {
303561
+ if (change.type === CanonicalChangeType.Structural) {
303562
+ const structuralResult = planStructuralDecision({
303563
+ ops,
303564
+ change,
303565
+ decision,
303566
+ removedRanges,
303567
+ retired
303568
+ });
303569
+ if (!structuralResult.ok)
303570
+ return {
303571
+ ok: false,
303572
+ failure: structuralResult.failure
303573
+ };
303574
+ } else if (!isFull && (change.type === CanonicalChangeType.Insertion || change.type === CanonicalChangeType.Deletion)) {
302608
303575
  const partialResult = planPartialTextDecision({
302609
303576
  ops,
302610
303577
  change,
@@ -302665,20 +303632,54 @@ var Node$13 = class Node$14 {
302665
303632
  failure: failure$3("CAPABILITY_UNAVAILABLE", `unsupported change type "${change.type}" for change "${change.id}".`)
302666
303633
  };
302667
303634
  }
303635
+ if (structuralTableStays.length > 0) {
303636
+ const decidedObjects = new Set(selections.map((selection) => selection.change));
303637
+ const seenStaying = /* @__PURE__ */ new Set;
303638
+ for (const change of graph.changes.values()) {
303639
+ if (seenStaying.has(change))
303640
+ continue;
303641
+ seenStaying.add(change);
303642
+ if (decidedObjects.has(change) || cascadedInsideStayingTable.has(change.id))
303643
+ continue;
303644
+ if (!isInsideStayingTable(change))
303645
+ continue;
303646
+ const failureResult = planContainedInlineChild(change);
303647
+ if (failureResult)
303648
+ return {
303649
+ ok: false,
303650
+ failure: failureResult
303651
+ };
303652
+ }
303653
+ }
302668
303654
  if (!ops.length)
302669
303655
  return {
302670
303656
  ok: false,
302671
303657
  failure: failure$3("NO_OP", "decision target produced no operations.", { details: { selections: selections.map((s2) => s2.change.id) } })
302672
303658
  };
302673
303659
  const affectedChildren = [];
303660
+ for (const id2 of suppressedInsideTable)
303661
+ affectedChildren.push({ changeId: id2 });
303662
+ for (const id2 of cascadedInsideStayingTable)
303663
+ affectedChildren.push({ changeId: id2 });
303664
+ const seenChange = /* @__PURE__ */ new Set;
302674
303665
  for (const change of graph.changes.values()) {
303666
+ if (seenChange.has(change))
303667
+ continue;
303668
+ seenChange.add(change);
302675
303669
  if (touched.has(change.id))
302676
303670
  continue;
303671
+ const insideRemoved = change.segments.length ? change.segments.every((seg) => removedRanges.some((r$1) => r$1.from <= seg.from && r$1.to >= seg.to)) : false;
303672
+ if (insideRemoved && isInsideRemovedTable(change)) {
303673
+ retired.add(change.id);
303674
+ touched.add(change.id);
303675
+ affectedChildren.push({ changeId: change.id });
303676
+ continue;
303677
+ }
302677
303678
  if (!change.parent)
302678
303679
  continue;
302679
303680
  if (!retired.has(change.parent) && !touched.has(change.parent))
302680
303681
  continue;
302681
- if (change.segments.every((seg) => removedRanges.some((r$1) => r$1.from <= seg.from && r$1.to >= seg.to))) {
303682
+ if (insideRemoved) {
302682
303683
  retired.add(change.id);
302683
303684
  touched.add(change.id);
302684
303685
  affectedChildren.push({ changeId: change.id });
@@ -302786,6 +303787,46 @@ var Node$13 = class Node$14 {
302786
303787
  });
302787
303788
  if (isFull)
302788
303789
  retired.add(change.id);
303790
+ }, planStructuralDecision = ({ ops, change, decision, removedRanges, retired }) => {
303791
+ const structural = change.structural;
303792
+ if (!structural)
303793
+ return {
303794
+ ok: false,
303795
+ failure: failure$3("PRECONDITION_FAILED", `structural change "${change.id}" is missing its structural payload.`)
303796
+ };
303797
+ if (structural.decidable === false || !structural.wholeTable)
303798
+ return {
303799
+ ok: false,
303800
+ failure: failure$3("CAPABILITY_UNAVAILABLE", "structural row-level revisions (partial rows or mixed sides) are not decidable; only whole-table insert/delete is supported.", { details: {
303801
+ changeId: change.id,
303802
+ reason: structural.undecidableReason ?? "not-whole-table"
303803
+ } })
303804
+ };
303805
+ if (structural.side === "insertion" && decision === "reject" || structural.side === "deletion" && decision === "accept") {
303806
+ ops.push({
303807
+ kind: "removeContent",
303808
+ from: structural.tableFrom,
303809
+ to: structural.tableTo,
303810
+ changeId: change.id,
303811
+ side: structural.side === "insertion" ? SegmentSide.Inserted : SegmentSide.Deleted
303812
+ });
303813
+ removedRanges.push({
303814
+ from: structural.tableFrom,
303815
+ to: structural.tableTo,
303816
+ cause: `${decision}-structural:${change.id}`
303817
+ });
303818
+ retired.add(change.id);
303819
+ return { ok: true };
303820
+ }
303821
+ for (const row2 of structural.rows)
303822
+ ops.push({
303823
+ kind: "clearRowTrackChange",
303824
+ from: row2.from,
303825
+ to: row2.to,
303826
+ changeId: change.id
303827
+ });
303828
+ retired.add(change.id);
303829
+ return { ok: true };
302789
303830
  }, planReplacementDecision = ({ ops, graph, change, decision, removedRanges, retired }) => {
302790
303831
  const inserted = change.insertedSegments;
302791
303832
  const deleted = change.deletedSegments;
@@ -303228,6 +304269,16 @@ var Node$13 = class Node$14 {
303228
304269
  tr.step(new RemoveMarkStep(op.from, op.to, op.mark));
303229
304270
  continue;
303230
304271
  }
304272
+ if (op.kind === "clearRowTrackChange") {
304273
+ const mappedFrom = tr.mapping.map(op.from, 1);
304274
+ const rowNode = tr.doc.nodeAt(mappedFrom);
304275
+ if (rowNode && rowNode.type.name === "tableRow")
304276
+ tr.setNodeMarkup(mappedFrom, undefined, {
304277
+ ...rowNode.attrs,
304278
+ trackChange: null
304279
+ });
304280
+ continue;
304281
+ }
303231
304282
  }
303232
304283
  for (const op of contentOps)
303233
304284
  tr.step(new ReplaceStep(op.from, op.to, Slice.empty));
@@ -307819,6 +308870,7 @@ var Node$13 = class Node$14 {
307819
308870
  runtimeRef,
307820
308871
  story: locator,
307821
308872
  type,
308873
+ subtype: type === "structural" && change.structural ? change.structural.subtype : undefined,
307822
308874
  author: toNonEmptyString(change.attrs.author),
307823
308875
  authorEmail: toNonEmptyString(change.attrs.authorEmail),
307824
308876
  authorImage: toNonEmptyString(change.attrs.authorImage),
@@ -310310,6 +311362,45 @@ var Node$13 = class Node$14 {
310310
311362
  .superdoc-layout .track-format-dec.highlighted.track-change-focused {
310311
311363
  background-color: var(--sd-tracked-changes-format-background-focused, #ffd70033);
310312
311364
  }
311365
+
311366
+ /*
311367
+ * Structural row-level tracked changes (inserted/deleted whole rows).
311368
+ *
311369
+ * The painter renders a row as absolutely-positioned cell <div>s (no <tr>), so
311370
+ * each cell of a tracked row carries the same base class (track-insert-dec /
311371
+ * track-delete-dec) + modifier (highlighted / hidden) as inline runs, plus the
311372
+ * block-context marker class track-row-cell-dec. These rules reuse the same
311373
+ * --sd-tracked-changes-insert-* / --sd-tracked-changes-delete-* CSS variables so
311374
+ * the per-author color flows through identically to the inline path.
311375
+ *
311376
+ * 'hidden' mode collapses the cell (and therefore the row) via the existing
311377
+ * .track-insert-dec.hidden / .track-delete-dec.hidden { display: none } rule
311378
+ * above: an inserted row in 'original' mode and a deleted row in 'final' mode
311379
+ * disappear, matching inline behavior.
311380
+ */
311381
+ .superdoc-layout .track-row-cell-dec.track-insert-dec.highlighted {
311382
+ background-color: var(--sd-tracked-changes-insert-background, #399c7222);
311383
+ border-top: var(--sd-tracked-changes-insert-border-width, 2px) solid
311384
+ var(--sd-tracked-changes-insert-border, #00853d);
311385
+ border-bottom: var(--sd-tracked-changes-insert-border-width, 2px) solid
311386
+ var(--sd-tracked-changes-insert-border, #00853d);
311387
+ }
311388
+
311389
+ .superdoc-layout .track-row-cell-dec.track-delete-dec.highlighted {
311390
+ background-color: var(--sd-tracked-changes-delete-background, #cb0e4722);
311391
+ border-top: var(--sd-tracked-changes-delete-border-width, 2px) solid
311392
+ var(--sd-tracked-changes-delete-border, #cb0e47);
311393
+ border-bottom: var(--sd-tracked-changes-delete-border-width, 2px) solid
311394
+ var(--sd-tracked-changes-delete-border, #cb0e47);
311395
+ }
311396
+
311397
+ .superdoc-layout .track-row-cell-dec.track-delete-dec.highlighted .superdoc-line {
311398
+ text-decoration:
311399
+ line-through
311400
+ solid
311401
+ var(--sd-tracked-changes-delete-text, #cb0e47)
311402
+ var(--sd-tracked-changes-delete-decoration-thickness, 2px);
311403
+ }
310313
311404
  `, FORMATTING_MARKS_STYLES = `
310314
311405
  .superdoc-formatting-space-mark,
310315
311406
  .superdoc-marker-suffix-space {
@@ -313690,6 +314781,125 @@ menclose::after {
313690
314781
  }
313691
314782
  }
313692
314783
  return { cellElement: cellEl };
314784
+ }, TRACK_CHANGE_BASE_CLASS, TRACK_CHANGE_OVERLAP_INSERT_DELETE_CLASS = "track-overlap-insert-delete-dec", TRACK_CHANGE_BACKGROUND_ALPHA = 34, TRACK_CHANGE_BACKGROUND_FOCUSED_ALPHA = 68, expandHexColor = (hex) => {
314785
+ const normalized = hex.replace("#", "");
314786
+ if (normalized.length === 3)
314787
+ return normalized.split("").map((char) => char + char).join("");
314788
+ if (normalized.length === 6 || normalized.length === 8)
314789
+ return normalized.slice(0, 6);
314790
+ return null;
314791
+ }, colorWithAlpha = (color2, alpha) => {
314792
+ const expanded = color2.trim().startsWith("#") ? expandHexColor(color2.trim()) : null;
314793
+ if (!expanded)
314794
+ return color2;
314795
+ return `#${expanded}${Math.max(0, Math.min(255, alpha)).toString(16).padStart(2, "0")}`;
314796
+ }, setColorVar = (elem, name, value) => {
314797
+ elem.style.setProperty(name, value);
314798
+ }, applyAuthorColorVariables = (elem, layer) => {
314799
+ const color2 = layer.color;
314800
+ if (!color2)
314801
+ return;
314802
+ const background = colorWithAlpha(color2, TRACK_CHANGE_BACKGROUND_ALPHA);
314803
+ const backgroundFocused = colorWithAlpha(color2, TRACK_CHANGE_BACKGROUND_FOCUSED_ALPHA);
314804
+ switch (layer.kind) {
314805
+ case "insert":
314806
+ setColorVar(elem, "--sd-tracked-changes-insert-border", color2);
314807
+ setColorVar(elem, "--sd-tracked-changes-insert-background", background);
314808
+ setColorVar(elem, "--sd-tracked-changes-insert-background-focused", backgroundFocused);
314809
+ break;
314810
+ case "delete":
314811
+ setColorVar(elem, "--sd-tracked-changes-delete-border", color2);
314812
+ setColorVar(elem, "--sd-tracked-changes-delete-background", background);
314813
+ setColorVar(elem, "--sd-tracked-changes-delete-background-focused", backgroundFocused);
314814
+ setColorVar(elem, "--sd-tracked-changes-delete-text", color2);
314815
+ break;
314816
+ case "format":
314817
+ setColorVar(elem, "--sd-tracked-changes-format-border", color2);
314818
+ setColorVar(elem, "--sd-tracked-changes-format-background", background);
314819
+ setColorVar(elem, "--sd-tracked-changes-format-background-focused", backgroundFocused);
314820
+ break;
314821
+ default:
314822
+ break;
314823
+ }
314824
+ }, TRACK_CHANGE_MODIFIER_CLASS, getTrackedChangeLayers$1 = (run2) => {
314825
+ if (Array.isArray(run2.trackedChanges) && run2.trackedChanges.length > 0)
314826
+ return run2.trackedChanges;
314827
+ return run2.trackedChange ? [run2.trackedChange] : [];
314828
+ }, resolveInsertDeleteOverlap = (layers) => {
314829
+ for (const parentInsert of layers) {
314830
+ if (parentInsert.kind !== "insert")
314831
+ continue;
314832
+ const childDelete = layers.find((layer) => layer.kind === "delete" && layer.overlapParentId === parentInsert.id);
314833
+ if (childDelete)
314834
+ return {
314835
+ parentInsert,
314836
+ childDelete
314837
+ };
314838
+ }
314839
+ }, resolveTrackedChangesConfig = (block) => {
314840
+ const attrs = block.attrs ?? {};
314841
+ return {
314842
+ mode: attrs.trackedChangesMode ?? "review",
314843
+ enabled: attrs.trackedChangesEnabled !== false
314844
+ };
314845
+ }, TRACK_CHANGE_ROW_CELL_CLASS = "track-row-cell-dec", applyRowTrackedChangeToCell = (elem, meta2, config2) => {
314846
+ if (!config2.enabled || config2.mode === "off")
314847
+ return;
314848
+ if (meta2.kind !== "insert" && meta2.kind !== "delete")
314849
+ return;
314850
+ const baseClass = TRACK_CHANGE_BASE_CLASS[meta2.kind];
314851
+ if (baseClass)
314852
+ elem.classList.add(baseClass);
314853
+ elem.classList.add(TRACK_CHANGE_ROW_CELL_CLASS);
314854
+ const modifier = TRACK_CHANGE_MODIFIER_CLASS[meta2.kind]?.[config2.mode];
314855
+ if (modifier)
314856
+ elem.classList.add(modifier);
314857
+ applyAuthorColorVariables(elem, meta2);
314858
+ elem.dataset.trackChangeId = meta2.id;
314859
+ elem.dataset.trackChangeKind = meta2.kind;
314860
+ elem.dataset.trackChangeStructural = "row";
314861
+ elem.dataset.storyKey = meta2.storyKey ?? "body";
314862
+ if (meta2.author)
314863
+ elem.dataset.trackChangeAuthor = meta2.author;
314864
+ if (meta2.authorEmail)
314865
+ elem.dataset.trackChangeAuthorEmail = meta2.authorEmail;
314866
+ if (meta2.date)
314867
+ elem.dataset.trackChangeDate = meta2.date;
314868
+ }, applyTrackedChangeDecorations = (elem, run2, config2) => {
314869
+ if (!config2.enabled || config2.mode === "off")
314870
+ return;
314871
+ const textRun = run2;
314872
+ const layers = getTrackedChangeLayers$1(textRun);
314873
+ if (layers.length === 0)
314874
+ return;
314875
+ const overlap = resolveInsertDeleteOverlap(layers);
314876
+ const meta2 = overlap?.parentInsert ?? textRun.trackedChange ?? layers[0];
314877
+ layers.forEach((layer) => {
314878
+ const baseClass = TRACK_CHANGE_BASE_CLASS[layer.kind];
314879
+ if (baseClass)
314880
+ elem.classList.add(baseClass);
314881
+ const modifier = TRACK_CHANGE_MODIFIER_CLASS[layer.kind]?.[config2.mode];
314882
+ if (modifier)
314883
+ elem.classList.add(modifier);
314884
+ applyAuthorColorVariables(elem, layer);
314885
+ });
314886
+ if (overlap) {
314887
+ elem.classList.add(TRACK_CHANGE_OVERLAP_INSERT_DELETE_CLASS);
314888
+ elem.dataset.trackChangePreferredTargetId = overlap.childDelete.id;
314889
+ }
314890
+ elem.dataset.trackChangeId = meta2.id;
314891
+ elem.dataset.trackChangeKind = meta2.kind;
314892
+ elem.dataset.trackChangeIds = layers.map((layer) => layer.id).join(",");
314893
+ elem.dataset.trackChangeKinds = layers.map((layer) => layer.kind).join(",");
314894
+ elem.dataset.storyKey = meta2.storyKey ?? "body";
314895
+ if (meta2.author)
314896
+ elem.dataset.trackChangeAuthor = meta2.author;
314897
+ if (meta2.authorEmail)
314898
+ elem.dataset.trackChangeAuthorEmail = meta2.authorEmail;
314899
+ if (meta2.authorImage)
314900
+ elem.dataset.trackChangeAuthorImage = meta2.authorImage;
314901
+ if (meta2.date)
314902
+ elem.dataset.trackChangeDate = meta2.date;
313693
314903
  }, hasAnyResolvedBorder = (borders) => Boolean(borders.top || borders.right || borders.bottom || borders.left), resolveRenderedCellBorders = ({ cellBorders, hasBordersAttribute, tableBorders, cellPosition, cellSpacingPx, continuesFromPrev, continuesOnNext, aboveCellBorders, leftCellBorders, rightCellBorders, nextRowLeavesRightGap, deferTopToAboveCell, nextRowSuppressesSharedTop }) => {
313694
314904
  const hasExplicitBorders = hasExplicitCellBorders(cellBorders);
313695
314905
  const cellBounds = getTableCellGridBounds(cellPosition);
@@ -313742,6 +314952,22 @@ menclose::after {
313742
314952
  }, renderTableRow = (deps) => {
313743
314953
  const { doc: doc$12, container, rowIndex, y: y$1, rowMeasure, row: row2, prevRow, prevRowMeasure, nextRow, nextRowMeasure, rowOccupiedRightCol, nextRowOccupiedRightCol, totalRows, tableBorders, columnWidths, allRowHeights, tableIndent, isRtl, context, renderLine: renderLine$1, captureLineSnapshot, renderDrawingContent, applySdtDataset: applySdtDataset$1, ancestorContainerKey, ancestorContainerSdt, ancestorContainerKeys, ancestorContainerSdts, onSdtContainerChrome, continuesFromPrev, continuesOnNext, partialRow, cellSpacingPx = 0, chrome: chrome2, resolvePhysical } = deps;
313744
314954
  const totalCols = columnWidths.length;
314955
+ const rowTrackedChange = row2?.attrs?.trackedChange;
314956
+ let rowTrackedChangeConfig;
314957
+ if (rowTrackedChange) {
314958
+ let representativeParagraph;
314959
+ for (const cell2 of row2?.cells ?? []) {
314960
+ const candidate = cell2.paragraph ?? cell2.blocks?.find((block) => block.kind === "paragraph");
314961
+ if (candidate) {
314962
+ representativeParagraph = candidate;
314963
+ break;
314964
+ }
314965
+ }
314966
+ rowTrackedChangeConfig = representativeParagraph ? resolveTrackedChangesConfig(representativeParagraph) : {
314967
+ mode: "review",
314968
+ enabled: true
314969
+ };
314970
+ }
313745
314971
  const rowRightEdgeCol = rowOccupiedRightCol != null && rowOccupiedRightCol > 0 ? Math.min(totalCols, rowOccupiedRightCol) : rowMeasure.cells.length ? Math.min(totalCols, Math.max(...rowMeasure.cells.map((c) => (c.gridColumnStart ?? 0) + (c.colSpan ?? 1)))) : totalCols;
313746
314972
  const rowBorderOverride = row2?.attrs?.borders;
313747
314973
  const effectiveTableBorders = rowBorderOverride ? {
@@ -313876,6 +315102,8 @@ menclose::after {
313876
315102
  chrome: chrome2,
313877
315103
  resolvePhysical
313878
315104
  });
315105
+ if (rowTrackedChange && rowTrackedChangeConfig)
315106
+ applyRowTrackedChangeToCell(cellElement, rowTrackedChange, rowTrackedChangeConfig);
313879
315107
  container.appendChild(cellElement);
313880
315108
  }
313881
315109
  }, renderTableFragment = (deps) => {
@@ -316190,102 +317418,6 @@ menclose::after {
316190
317418
  });
316191
317419
  return createErrorPlaceholder(fragment2.blockId, error3);
316192
317420
  }
316193
- }, TRACK_CHANGE_BASE_CLASS, TRACK_CHANGE_OVERLAP_INSERT_DELETE_CLASS = "track-overlap-insert-delete-dec", TRACK_CHANGE_BACKGROUND_ALPHA = 34, TRACK_CHANGE_BACKGROUND_FOCUSED_ALPHA = 68, expandHexColor = (hex) => {
316194
- const normalized = hex.replace("#", "");
316195
- if (normalized.length === 3)
316196
- return normalized.split("").map((char) => char + char).join("");
316197
- if (normalized.length === 6 || normalized.length === 8)
316198
- return normalized.slice(0, 6);
316199
- return null;
316200
- }, colorWithAlpha = (color2, alpha) => {
316201
- const expanded = color2.trim().startsWith("#") ? expandHexColor(color2.trim()) : null;
316202
- if (!expanded)
316203
- return color2;
316204
- return `#${expanded}${Math.max(0, Math.min(255, alpha)).toString(16).padStart(2, "0")}`;
316205
- }, setColorVar = (elem, name, value) => {
316206
- elem.style.setProperty(name, value);
316207
- }, applyAuthorColorVariables = (elem, layer) => {
316208
- const color2 = layer.color;
316209
- if (!color2)
316210
- return;
316211
- const background = colorWithAlpha(color2, TRACK_CHANGE_BACKGROUND_ALPHA);
316212
- const backgroundFocused = colorWithAlpha(color2, TRACK_CHANGE_BACKGROUND_FOCUSED_ALPHA);
316213
- switch (layer.kind) {
316214
- case "insert":
316215
- setColorVar(elem, "--sd-tracked-changes-insert-border", color2);
316216
- setColorVar(elem, "--sd-tracked-changes-insert-background", background);
316217
- setColorVar(elem, "--sd-tracked-changes-insert-background-focused", backgroundFocused);
316218
- break;
316219
- case "delete":
316220
- setColorVar(elem, "--sd-tracked-changes-delete-border", color2);
316221
- setColorVar(elem, "--sd-tracked-changes-delete-background", background);
316222
- setColorVar(elem, "--sd-tracked-changes-delete-background-focused", backgroundFocused);
316223
- setColorVar(elem, "--sd-tracked-changes-delete-text", color2);
316224
- break;
316225
- case "format":
316226
- setColorVar(elem, "--sd-tracked-changes-format-border", color2);
316227
- setColorVar(elem, "--sd-tracked-changes-format-background", background);
316228
- setColorVar(elem, "--sd-tracked-changes-format-background-focused", backgroundFocused);
316229
- break;
316230
- default:
316231
- break;
316232
- }
316233
- }, TRACK_CHANGE_MODIFIER_CLASS, getTrackedChangeLayers$1 = (run2) => {
316234
- if (Array.isArray(run2.trackedChanges) && run2.trackedChanges.length > 0)
316235
- return run2.trackedChanges;
316236
- return run2.trackedChange ? [run2.trackedChange] : [];
316237
- }, resolveInsertDeleteOverlap = (layers) => {
316238
- for (const parentInsert of layers) {
316239
- if (parentInsert.kind !== "insert")
316240
- continue;
316241
- const childDelete = layers.find((layer) => layer.kind === "delete" && layer.overlapParentId === parentInsert.id);
316242
- if (childDelete)
316243
- return {
316244
- parentInsert,
316245
- childDelete
316246
- };
316247
- }
316248
- }, resolveTrackedChangesConfig = (block) => {
316249
- const attrs = block.attrs ?? {};
316250
- return {
316251
- mode: attrs.trackedChangesMode ?? "review",
316252
- enabled: attrs.trackedChangesEnabled !== false
316253
- };
316254
- }, applyTrackedChangeDecorations = (elem, run2, config2) => {
316255
- if (!config2.enabled || config2.mode === "off")
316256
- return;
316257
- const textRun = run2;
316258
- const layers = getTrackedChangeLayers$1(textRun);
316259
- if (layers.length === 0)
316260
- return;
316261
- const overlap = resolveInsertDeleteOverlap(layers);
316262
- const meta2 = overlap?.parentInsert ?? textRun.trackedChange ?? layers[0];
316263
- layers.forEach((layer) => {
316264
- const baseClass = TRACK_CHANGE_BASE_CLASS[layer.kind];
316265
- if (baseClass)
316266
- elem.classList.add(baseClass);
316267
- const modifier = TRACK_CHANGE_MODIFIER_CLASS[layer.kind]?.[config2.mode];
316268
- if (modifier)
316269
- elem.classList.add(modifier);
316270
- applyAuthorColorVariables(elem, layer);
316271
- });
316272
- if (overlap) {
316273
- elem.classList.add(TRACK_CHANGE_OVERLAP_INSERT_DELETE_CLASS);
316274
- elem.dataset.trackChangePreferredTargetId = overlap.childDelete.id;
316275
- }
316276
- elem.dataset.trackChangeId = meta2.id;
316277
- elem.dataset.trackChangeKind = meta2.kind;
316278
- elem.dataset.trackChangeIds = layers.map((layer) => layer.id).join(",");
316279
- elem.dataset.trackChangeKinds = layers.map((layer) => layer.kind).join(",");
316280
- elem.dataset.storyKey = meta2.storyKey ?? "body";
316281
- if (meta2.author)
316282
- elem.dataset.trackChangeAuthor = meta2.author;
316283
- if (meta2.authorEmail)
316284
- elem.dataset.trackChangeAuthorEmail = meta2.authorEmail;
316285
- if (meta2.authorImage)
316286
- elem.dataset.trackChangeAuthorImage = meta2.authorImage;
316287
- if (meta2.date)
316288
- elem.dataset.trackChangeDate = meta2.date;
316289
317421
  }, ACTIVE_HEADER_FOOTER_WATERMARK_PREVIEW_OPACITY = "1", INACTIVE_HEADER_FOOTER_WATERMARK_PREVIEW_OPACITY = "0.5", resolveOrBuildFragmentIdentity = (fragment2, story, existing) => buildLayoutSourceIdentityForFragment(existing ? {
316290
317422
  ...fragment2,
316291
317423
  layoutSourceIdentity: existing,
@@ -328059,13 +329191,13 @@ menclose::after {
328059
329191
  return;
328060
329192
  console.log(...args$1);
328061
329193
  }, HEADER_FOOTER_INIT_BUDGET_MS = 200, MAX_ZOOM_WARNING_THRESHOLD = 10, MAX_SELECTION_RECTS_PER_USER = 100, SEMANTIC_RESIZE_DEBOUNCE_MS = 120, MIN_SEMANTIC_CONTENT_WIDTH_PX = 1, GLOBAL_PERFORMANCE, PresentationEditor, ICONS, TEXTS, tableActionsOptions, TRACKED_MARK_NAMES;
328062
- var init_src_eTZqPcFn_es = __esm(() => {
329194
+ var init_src_DeS9kJS7_es = __esm(() => {
328063
329195
  init_rolldown_runtime_Bg48TavK_es();
328064
- init_SuperConverter_D2zNnC50_es();
329196
+ init_SuperConverter_BBjNvGFh_es();
328065
329197
  init_jszip_C49i9kUs_es();
328066
329198
  init_xml_js_CqGKpaft_es();
328067
329199
  init_uuid_qzgm05fK_es();
328068
- init_create_headless_toolbar_COmoIa5Q_es();
329200
+ init_create_headless_toolbar_s_kl3MP8_es();
328069
329201
  init_constants_D9qj59G2_es();
328070
329202
  init_dist_B8HfvhaK_es();
328071
329203
  init_unified_Dsuw2be5_es();
@@ -333282,7 +334414,12 @@ ${err.toString()}`);
333282
334414
  rsidRPr: { rendered: false },
333283
334415
  rsidTr: { rendered: false },
333284
334416
  paraId: { rendered: false },
333285
- textId: { rendered: false }
334417
+ textId: { rendered: false },
334418
+ trackChange: {
334419
+ default: null,
334420
+ keepOnSplit: true,
334421
+ rendered: false
334422
+ }
333286
334423
  };
333287
334424
  },
333288
334425
  parseDOM() {
@@ -340162,13 +341299,16 @@ ${err.toString()}`);
340162
341299
  Insertion: "insertion",
340163
341300
  Deletion: "deletion",
340164
341301
  Replacement: "replacement",
340165
- Formatting: "formatting"
341302
+ Formatting: "formatting",
341303
+ Structural: "structural"
340166
341304
  });
340167
341305
  ChangeSubtype = Object.freeze({
340168
341306
  TextInsertion: "text-insertion",
340169
341307
  TextDeletion: "text-deletion",
340170
341308
  TextReplacement: "text-replacement",
340171
- RunFormatting: "run-formatting"
341309
+ RunFormatting: "run-formatting",
341310
+ TableInsert: "table-insert",
341311
+ TableDelete: "table-delete"
340172
341312
  });
340173
341313
  SegmentSide = Object.freeze({
340174
341314
  Inserted: "inserted",
@@ -355286,6 +356426,31 @@ function print() { __p += __j.call(arguments, '') }
355286
356426
  RTL_DATE_LIKE_TOKEN_RE = /^-?\d+(?:[./-]\d+)+$/;
355287
356427
  STRONG_RTL_CHAR_RE = /[\u0590-\u08FF\p{Script=Hebrew}\p{Script=Arabic}]/u;
355288
356428
  LATIN_DIGIT_NEUTRAL_ONLY_RE = /^[\s0-9A-Za-z./\-_:,+()]+$/;
356429
+ TRACK_CHANGE_BASE_CLASS = {
356430
+ insert: "track-insert-dec",
356431
+ delete: "track-delete-dec",
356432
+ format: "track-format-dec"
356433
+ };
356434
+ TRACK_CHANGE_MODIFIER_CLASS = {
356435
+ insert: {
356436
+ review: "highlighted",
356437
+ original: "hidden",
356438
+ final: "normal",
356439
+ off: undefined
356440
+ },
356441
+ delete: {
356442
+ review: "highlighted",
356443
+ original: "normal",
356444
+ final: "hidden",
356445
+ off: undefined
356446
+ },
356447
+ format: {
356448
+ review: "highlighted",
356449
+ original: "before",
356450
+ final: "normal",
356451
+ off: undefined
356452
+ }
356453
+ };
355289
356454
  SDT_DATASET_KEYS = [
355290
356455
  "sdtType",
355291
356456
  "sdtId",
@@ -355454,31 +356619,6 @@ function print() { __p += __j.call(arguments, '') }
355454
356619
  "m:fName",
355455
356620
  "m:oMath"
355456
356621
  ]);
355457
- TRACK_CHANGE_BASE_CLASS = {
355458
- insert: "track-insert-dec",
355459
- delete: "track-delete-dec",
355460
- format: "track-format-dec"
355461
- };
355462
- TRACK_CHANGE_MODIFIER_CLASS = {
355463
- insert: {
355464
- review: "highlighted",
355465
- original: "hidden",
355466
- final: "normal",
355467
- off: undefined
355468
- },
355469
- delete: {
355470
- review: "highlighted",
355471
- original: "normal",
355472
- final: "hidden",
355473
- off: undefined
355474
- },
355475
- format: {
355476
- review: "highlighted",
355477
- original: "before",
355478
- final: "normal",
355479
- off: undefined
355480
- }
355481
- };
355482
356622
  CLIP_PATH_PREFIXES = [
355483
356623
  "inset(",
355484
356624
  "polygon(",
@@ -357597,9 +358737,43 @@ function print() { __p += __j.call(arguments, '') }
357597
358737
  storyKey: BODY_STORY_KEY
357598
358738
  }),
357599
358739
  ...this.#collectIndexedTrackedChangePositions(),
358740
+ ...this.#collectStructuralBodyTrackedChangePositions(),
357600
358741
  ...this.#collectRenderedTrackedChangePositions()
357601
358742
  };
357602
358743
  }
358744
+ #collectStructuralBodyTrackedChangePositions() {
358745
+ const positions = {};
358746
+ let snapshots = [];
358747
+ try {
358748
+ snapshots = getTrackedChangeIndex(this.#editor).getAll();
358749
+ } catch {
358750
+ return positions;
358751
+ }
358752
+ snapshots.forEach((snapshot2) => {
358753
+ if (snapshot2?.type !== "structural")
358754
+ return;
358755
+ const storyKey = typeof snapshot2?.runtimeRef?.storyKey === "string" ? snapshot2.runtimeRef.storyKey : BODY_STORY_KEY;
358756
+ if (storyKey !== "body")
358757
+ return;
358758
+ const key2 = typeof snapshot2?.anchorKey === "string" ? snapshot2.anchorKey : null;
358759
+ const rawId = snapshot2?.runtimeRef?.rawId;
358760
+ const threadId = rawId == null ? null : String(rawId);
358761
+ if (!key2 || !threadId || positions[key2])
358762
+ return;
358763
+ const start$1 = Number.isFinite(snapshot2?.range?.from) ? Number(snapshot2.range.from) : undefined;
358764
+ const end$1 = Number.isFinite(snapshot2?.range?.to) ? Number(snapshot2.range.to) : undefined;
358765
+ positions[key2] = {
358766
+ threadId,
358767
+ key: key2,
358768
+ storyKey,
358769
+ kind: "trackedChange",
358770
+ structural: true,
358771
+ ...start$1 !== undefined ? { start: start$1 } : {},
358772
+ ...end$1 !== undefined ? { end: end$1 } : {}
358773
+ };
358774
+ });
358775
+ return positions;
358776
+ }
357603
358777
  #collectIndexedTrackedChangePositions() {
357604
358778
  const positions = {};
357605
358779
  let snapshots = [];
@@ -363103,11 +364277,11 @@ function print() { __p += __j.call(arguments, '') }
363103
364277
  ]);
363104
364278
  });
363105
364279
 
363106
- // ../../packages/superdoc/dist/chunks/create-super-doc-ui-BOYlxpy0.es.js
364280
+ // ../../packages/superdoc/dist/chunks/create-super-doc-ui-CZZRzAFm.es.js
363107
364281
  var MOD_ALIASES, ALT_ALIASES, CTRL_ALIASES, SHIFT_ALIASES, BUILTIN_CONTEXT_MENU_GROUPS, BUILTIN_GROUP_ORDER, RESERVED_PROXY_PROPERTY_NAMES, ALL_TOOLBAR_COMMAND_IDS, EMPTY_ACTIVE_IDS;
363108
- var init_create_super_doc_ui_BOYlxpy0_es = __esm(() => {
363109
- init_SuperConverter_D2zNnC50_es();
363110
- init_create_headless_toolbar_COmoIa5Q_es();
364282
+ var init_create_super_doc_ui_CZZRzAFm_es = __esm(() => {
364283
+ init_SuperConverter_BBjNvGFh_es();
364284
+ init_create_headless_toolbar_s_kl3MP8_es();
363111
364285
  MOD_ALIASES = new Set([
363112
364286
  "Mod",
363113
364287
  "Meta",
@@ -363149,16 +364323,16 @@ var init_zipper_yaJVJ4z9_es = __esm(() => {
363149
364323
 
363150
364324
  // ../../packages/superdoc/dist/super-editor.es.js
363151
364325
  var init_super_editor_es = __esm(() => {
363152
- init_src_eTZqPcFn_es();
363153
- init_SuperConverter_D2zNnC50_es();
364326
+ init_src_DeS9kJS7_es();
364327
+ init_SuperConverter_BBjNvGFh_es();
363154
364328
  init_jszip_C49i9kUs_es();
363155
364329
  init_xml_js_CqGKpaft_es();
363156
- init_create_headless_toolbar_COmoIa5Q_es();
364330
+ init_create_headless_toolbar_s_kl3MP8_es();
363157
364331
  init_constants_D9qj59G2_es();
363158
364332
  init_dist_B8HfvhaK_es();
363159
364333
  init_unified_Dsuw2be5_es();
363160
364334
  init_DocxZipper_Bu2Fhqkw_es();
363161
- init_create_super_doc_ui_BOYlxpy0_es();
364335
+ init_create_super_doc_ui_CZZRzAFm_es();
363162
364336
  init_ui_C5PAS9hY_es();
363163
364337
  init_eventemitter3_BnGqBE_Q_es();
363164
364338
  init_errors_CNaD6vcg_es();