docx-diff-editor 1.0.51 → 1.0.53

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.
package/README.md CHANGED
@@ -51,6 +51,10 @@ function App() {
51
51
  );
52
52
 
53
53
  console.log(`Found ${result.totalChanges} changes`);
54
+
55
+ // Note: Subsequent compareWith calls compare against current editor state
56
+ // (with track changes accepted), not the original source.
57
+ // To compare against original again, call setSource() first.
54
58
  };
55
59
 
56
60
  return (
@@ -117,7 +121,8 @@ interface DocxDiffEditorRef {
117
121
  // Set the source/base document
118
122
  setSource(content: DocxContent): Promise<void>;
119
123
 
120
- // Compare and show track changes
124
+ // Compare current editor content with new content, show track changes
125
+ // Note: Compares against current editor state (not original source)
121
126
  compareWith(content: DocxContent): Promise<ComparisonResult>;
122
127
 
123
128
  // Get diff data
package/dist/index.d.mts CHANGED
@@ -516,8 +516,12 @@ declare function createTrackDeleteMark(author?: TrackChangeAuthor, id?: string):
516
516
  *
517
517
  * Note: SuperDoc's parseFormatList requires all marks in before/after arrays
518
518
  * to have both `type` and `attrs` properties. Marks without `attrs` get filtered out,
519
- * causing empty values in track change bubbles. We normalize marks here to ensure
520
- * all have at least an empty `attrs` object.
519
+ * causing empty values in track change bubbles.
520
+ *
521
+ * We use normalizeMarksForTrackFormat which:
522
+ * 1. Ensures all marks have `attrs` property (required by parseFormatList)
523
+ * 2. Cleans attrs to remove null/undefined/empty values (prevents "Set X to undefined" bubbles)
524
+ * 3. Normalizes color values to valid CSS format
521
525
  */
522
526
  declare function createTrackFormatMark(before: ProseMirrorMark[], after: ProseMirrorMark[], author?: TrackChangeAuthor): ProseMirrorMark;
523
527
 
package/dist/index.d.ts CHANGED
@@ -516,8 +516,12 @@ declare function createTrackDeleteMark(author?: TrackChangeAuthor, id?: string):
516
516
  *
517
517
  * Note: SuperDoc's parseFormatList requires all marks in before/after arrays
518
518
  * to have both `type` and `attrs` properties. Marks without `attrs` get filtered out,
519
- * causing empty values in track change bubbles. We normalize marks here to ensure
520
- * all have at least an empty `attrs` object.
519
+ * causing empty values in track change bubbles.
520
+ *
521
+ * We use normalizeMarksForTrackFormat which:
522
+ * 1. Ensures all marks have `attrs` property (required by parseFormatList)
523
+ * 2. Cleans attrs to remove null/undefined/empty values (prevents "Set X to undefined" bubbles)
524
+ * 3. Normalizes color values to valid CSS format
521
525
  */
522
526
  declare function createTrackFormatMark(before: ProseMirrorMark[], after: ProseMirrorMark[], author?: TrackChangeAuthor): ProseMirrorMark;
523
527
 
package/dist/index.js CHANGED
@@ -541,6 +541,18 @@ function ensureValidCssColor(color) {
541
541
  }
542
542
 
543
543
  // src/services/trackChangeInjector.ts
544
+ function isMeaningfulValue(value) {
545
+ return value !== null && value !== void 0 && value !== "";
546
+ }
547
+ function cleanAttrs(attrs) {
548
+ const cleaned = {};
549
+ for (const [key, value] of Object.entries(attrs)) {
550
+ if (isMeaningfulValue(value)) {
551
+ cleaned[key] = value;
552
+ }
553
+ }
554
+ return cleaned;
555
+ }
544
556
  function normalizeMark(mark) {
545
557
  const attrs = { ...mark.attrs || {} };
546
558
  if (attrs.color !== void 0) {
@@ -551,9 +563,23 @@ function normalizeMark(mark) {
551
563
  attrs
552
564
  };
553
565
  }
566
+ function normalizeMarkForTrackFormat(mark) {
567
+ let attrs = { ...mark.attrs || {} };
568
+ if (attrs.color !== void 0) {
569
+ attrs.color = ensureValidCssColor(attrs.color);
570
+ }
571
+ attrs = cleanAttrs(attrs);
572
+ return {
573
+ type: mark.type,
574
+ attrs
575
+ };
576
+ }
554
577
  function normalizeMarks(marks) {
555
578
  return marks.map(normalizeMark);
556
579
  }
580
+ function normalizeMarksForTrackFormat(marks) {
581
+ return marks.map(normalizeMarkForTrackFormat);
582
+ }
557
583
  function normalizeMarksForRendering(marks) {
558
584
  return normalizeMarks(marks);
559
585
  }
@@ -582,8 +608,8 @@ function createTrackDeleteMark(author = DEFAULT_AUTHOR, id) {
582
608
  };
583
609
  }
584
610
  function createTrackFormatMark(before, after, author = DEFAULT_AUTHOR) {
585
- const normalizedBefore = normalizeMarks(before);
586
- const normalizedAfter = normalizeMarks(after);
611
+ const normalizedBefore = normalizeMarksForTrackFormat(before);
612
+ const normalizedAfter = normalizeMarksForTrackFormat(after);
587
613
  return {
588
614
  type: "trackFormat",
589
615
  attrs: {
@@ -3159,17 +3185,27 @@ var DocxDiffEditor = react.forwardRef(
3159
3185
  }
3160
3186
  },
3161
3187
  /**
3162
- * Compare source with new content, show track changes
3188
+ * Compare current editor content with new content, show track changes.
3189
+ *
3190
+ * The comparison uses the current editor state (with any existing track
3191
+ * changes accepted/stripped) as the baseline. This means if you've made
3192
+ * edits or accepted previous comparisons, those become the new baseline.
3193
+ *
3194
+ * To compare against the original source document, call setSource() again
3195
+ * before compareWith().
3163
3196
  */
3164
3197
  async compareWith(content) {
3165
3198
  if (!SuperDocRef.current) {
3166
3199
  throw new Error("Editor not initialized");
3167
3200
  }
3168
- if (!sourceJson) {
3169
- throw new Error("No source document set. Call setSource() first.");
3201
+ if (!superdocRef.current?.activeEditor) {
3202
+ throw new Error("Editor not ready. Ensure a document is loaded first.");
3170
3203
  }
3171
3204
  setIsLoading(true);
3172
3205
  try {
3206
+ const currentEditorJson = superdocRef.current.activeEditor.getJSON();
3207
+ const cleanBaseline = acceptAllChangesInJson(currentEditorJson) || { type: "doc", content: [] };
3208
+ setSourceJson(cleanBaseline);
3173
3209
  const contentType = detectContentType(content);
3174
3210
  let newJson;
3175
3211
  if (contentType === "file") {
@@ -3228,14 +3264,14 @@ var DocxDiffEditor = react.forwardRef(
3228
3264
  }
3229
3265
  const normalizedNewJson = normalizeRunProperties(newJson);
3230
3266
  const structuralResult = mergeWithStructuralAwareness(
3231
- sourceJson,
3267
+ cleanBaseline,
3232
3268
  normalizedNewJson,
3233
3269
  author
3234
3270
  );
3235
3271
  const merged = structuralResult.mergedDoc;
3236
3272
  const structInfos = structuralResult.structuralInfos;
3237
3273
  setMergedJson(merged);
3238
- const diff = diffDocuments(sourceJson, newJson);
3274
+ const diff = diffDocuments(cleanBaseline, newJson);
3239
3275
  setDiffResult(diff);
3240
3276
  if (superdocRef.current?.activeEditor) {
3241
3277
  setEditorContent(superdocRef.current.activeEditor, merged);