docx-diff-editor 1.0.60 → 1.0.62

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
@@ -106,7 +106,7 @@ await editor.setSource({ type: 'doc', content: [...] });
106
106
  | `onReady` | `() => void` | - | Called when editor is ready |
107
107
  | `onSourceLoaded` | `(json) => void` | - | Called when source is loaded |
108
108
  | `onComparisonComplete` | `(result) => void` | - | Called after comparison |
109
- | `onError` | `(error) => void` | - | Called on errors |
109
+ | `onError` | `(error: EditorError) => void` | - | Called on errors (see Error Handling) |
110
110
  | `className` | `string` | - | Container class |
111
111
  | `toolbarClassName` | `string` | - | Toolbar container class |
112
112
  | `editorClassName` | `string` | - | Editor container class |
@@ -119,11 +119,13 @@ await editor.setSource({ type: 'doc', content: [...] });
119
119
  ```tsx
120
120
  interface DocxDiffEditorRef {
121
121
  // Set the source/base document
122
- setSource(content: DocxContent): Promise<void>;
122
+ // Returns void on success, SetSourceError on failure (editor preserved)
123
+ setSource(content: DocxContent): Promise<void | SetSourceError>;
123
124
 
124
125
  // Compare current editor content with new content, show track changes
125
126
  // Note: Compares against current editor state (not original source)
126
- compareWith(content: DocxContent): Promise<ComparisonResult>;
127
+ // Returns ComparisonResult on success, ComparisonError on failure (editor preserved)
128
+ compareWith(content: DocxContent): Promise<CompareWithResult>;
127
129
 
128
130
  // Get diff data
129
131
  getDiffSegments(): DiffSegment[];
@@ -165,17 +167,86 @@ interface DocxDiffEditorRef {
165
167
 
166
168
  ```tsx
167
169
  interface ComparisonResult {
170
+ success: true; // Indicates successful comparison
168
171
  totalChanges: number;
169
172
  insertions: number;
170
173
  deletions: number;
171
174
  formatChanges: number;
172
- structuralChanges: number; // New: count of structural changes
175
+ structuralChanges: number;
173
176
  summary: string[];
174
177
  mergedJson: ProseMirrorJSON;
175
- structuralChangeInfos: StructuralChangeInfo[]; // New: metadata for pane
178
+ structuralChangeInfos: StructuralChangeInfo[];
179
+ usedFallback?: boolean; // True if track visualization unavailable
176
180
  }
177
181
  ```
178
182
 
183
+ ### Error Handling
184
+
185
+ The component provides graceful error handling that preserves the editor state on recoverable failures.
186
+
187
+ #### Error Types
188
+
189
+ ```tsx
190
+ interface EditorError {
191
+ error: Error; // The underlying error
192
+ type: 'fatal' | 'operation'; // Fatal = editor unusable, Operation = editor still works
193
+ operation?: 'setSource' | 'compareWith' | 'parseHtml' | 'export' | 'init';
194
+ recoverable: boolean; // True if editor is still functional
195
+ message: string; // Human-readable message
196
+ phase?: 'parsing' | 'diffing' | 'merging' | 'applying'; // For compareWith
197
+ }
198
+ ```
199
+
200
+ #### Result-Based Error Handling
201
+
202
+ Both `setSource()` and `compareWith()` return result objects instead of throwing:
203
+
204
+ ```tsx
205
+ // compareWith returns a union type
206
+ const result = await editorRef.current?.compareWith(newContent);
207
+
208
+ if (!result.success) {
209
+ // Editor is still intact! Show a friendly message
210
+ showModal({
211
+ title: 'Comparison Failed',
212
+ message: result.message,
213
+ phase: result.phase, // 'parsing', 'diffing', 'merging', or 'applying'
214
+ });
215
+ return;
216
+ }
217
+
218
+ // Success - access the usual fields
219
+ console.log(`Found ${result.totalChanges} changes`);
220
+ ```
221
+
222
+ #### Using the onError Callback
223
+
224
+ ```tsx
225
+ <DocxDiffEditor
226
+ ref={editorRef}
227
+ onError={(errorInfo) => {
228
+ if (errorInfo.type === 'fatal') {
229
+ // Editor is unusable - show full error page or reinitialize
230
+ console.error('Fatal editor error:', errorInfo.error);
231
+ } else {
232
+ // Editor still works - just show a notification
233
+ toast.error(`${errorInfo.operation} failed: ${errorInfo.message}`);
234
+ }
235
+ }}
236
+ />
237
+ ```
238
+
239
+ #### Recovery Behavior
240
+
241
+ When operations fail, the component attempts a multi-tier recovery:
242
+
243
+ 1. **Primary**: Apply the requested change
244
+ 2. **Fallback**: Try a simpler version (e.g., without track marks)
245
+ 3. **Rollback**: Restore the previous editor state
246
+ 4. **Fatal**: Only if all recovery attempts fail, show the error overlay
247
+
248
+ This ensures users don't lose their work due to invalid comparison content or parsing errors.
249
+
179
250
  ### DocumentInfo
180
251
 
181
252
  ```tsx
package/dist/index.d.mts CHANGED
@@ -170,9 +170,37 @@ interface StructuralChangeInfo {
170
170
  attrChanges?: AttrDiff[];
171
171
  }
172
172
  /**
173
- * Result returned after comparing two documents
173
+ * Operation types that can fail
174
+ */
175
+ type EditorOperation = 'setSource' | 'compareWith' | 'parseHtml' | 'export' | 'init';
176
+ /**
177
+ * Phase of compareWith where failure occurred
178
+ */
179
+ type ComparisonPhase = 'parsing' | 'diffing' | 'merging' | 'applying';
180
+ /**
181
+ * Enhanced error information passed to onError callback.
182
+ * Provides context about whether the error is recoverable and what operation failed.
183
+ */
184
+ interface EditorError {
185
+ /** The underlying Error object */
186
+ error: Error;
187
+ /** Error classification: 'fatal' means editor is unusable, 'operation' means editor is still functional */
188
+ type: 'fatal' | 'operation';
189
+ /** Which operation failed */
190
+ operation?: EditorOperation;
191
+ /** Whether the editor is still usable after this error */
192
+ recoverable: boolean;
193
+ /** Human-readable error message */
194
+ message: string;
195
+ /** For compareWith: which phase failed */
196
+ phase?: ComparisonPhase;
197
+ }
198
+ /**
199
+ * Successful result returned after comparing two documents
174
200
  */
175
201
  interface ComparisonResult {
202
+ /** Indicates successful comparison */
203
+ success: true;
176
204
  /** Total number of changes */
177
205
  totalChanges: number;
178
206
  /** Number of insertions */
@@ -197,6 +225,25 @@ interface ComparisonResult {
197
225
  */
198
226
  usedFallback?: boolean;
199
227
  }
228
+ /**
229
+ * Failed comparison result.
230
+ * Returned when compareWith fails but the editor is still functional.
231
+ */
232
+ interface ComparisonError {
233
+ /** Indicates failed comparison */
234
+ success: false;
235
+ /** The underlying error */
236
+ error: Error;
237
+ /** Human-readable error message */
238
+ message: string;
239
+ /** Which phase of comparison failed */
240
+ phase: ComparisonPhase;
241
+ }
242
+ /**
243
+ * Union type for compareWith return value.
244
+ * Check the `success` field to determine which type you have.
245
+ */
246
+ type CompareWithResult = ComparisonResult | ComparisonError;
200
247
  /**
201
248
  * Location context for a change
202
249
  */
@@ -326,8 +373,17 @@ interface DocxDiffEditorProps {
326
373
  onSourceLoaded?: (json: ProseMirrorJSON) => void;
327
374
  /** Callback when comparison completes */
328
375
  onComparisonComplete?: (result: ComparisonResult) => void;
329
- /** Callback on errors */
330
- onError?: (error: Error) => void;
376
+ /**
377
+ * Callback on errors.
378
+ *
379
+ * The EditorError object provides context about the error:
380
+ * - `type: 'fatal'` - Editor is unusable (overlay will be shown)
381
+ * - `type: 'operation'` - Operation failed but editor is still functional
382
+ *
383
+ * For operation errors, the editor remains visible and usable.
384
+ * You can use this callback to show a modal or toast notification.
385
+ */
386
+ onError?: (error: EditorError) => void;
331
387
  /** Container className */
332
388
  className?: string;
333
389
  /** Toolbar container className */
@@ -341,16 +397,40 @@ interface DocxDiffEditorProps {
341
397
  /** Hide structural changes pane entirely (default: false) */
342
398
  hideStructuralPane?: boolean;
343
399
  }
400
+ /**
401
+ * Error result for setSource operation
402
+ */
403
+ interface SetSourceError {
404
+ /** Indicates failure */
405
+ success: false;
406
+ /** The underlying error */
407
+ error: Error;
408
+ /** Human-readable error message */
409
+ message: string;
410
+ }
344
411
  /**
345
412
  * Ref methods exposed by DocxDiffEditor
346
413
  */
347
414
  interface DocxDiffEditorRef {
348
- /** Set the source/base document (destroys and recreates SuperDoc instance) */
349
- setSource(content: DocxContent): Promise<void>;
415
+ /**
416
+ * Set the source/base document (destroys and recreates SuperDoc instance).
417
+ *
418
+ * On failure, returns an error object instead of throwing. The editor
419
+ * will attempt to restore the previous state if possible.
420
+ */
421
+ setSource(content: DocxContent): Promise<void | SetSourceError>;
350
422
  /** Update content in the existing editor without recreating SuperDoc instance */
351
423
  updateContent(json: ProseMirrorJSON): void;
352
- /** Compare source with new content, show track changes */
353
- compareWith(content: DocxContent): Promise<ComparisonResult>;
424
+ /**
425
+ * Compare source with new content, show track changes.
426
+ *
427
+ * Returns a union type - check `result.success` to determine outcome:
428
+ * - `success: true` - Comparison succeeded, access result fields
429
+ * - `success: false` - Comparison failed, editor unchanged, check error
430
+ *
431
+ * On failure, the editor is preserved in its previous state.
432
+ */
433
+ compareWith(content: DocxContent): Promise<CompareWithResult>;
354
434
  /** Get raw diff segments */
355
435
  getDiffSegments(): DiffSegment[];
356
436
  /** Get enriched changes with context for LLM processing */
@@ -765,4 +845,4 @@ declare function getBlankTemplateBlob(): Blob;
765
845
  */
766
846
  declare function isValidDocxFile(file: File): boolean;
767
847
 
768
- export { type AttrDiff, type AttributeChange, CSS_PREFIX, type ChangeLocation, type ComparisonResult, DEFAULT_AUTHOR, DEFAULT_SUPERDOC_USER, type DiffResult, type DiffSegment, type DocumentInfo, type DocumentProperties, type DocxContent, DocxDiffEditor, type DocxDiffEditorProps, type DocxDiffEditorRef, type EnrichedChange, type FingerprintedNode, type FormatChange, type FormatDetails, type HybridDiffResult, type NodeMatch, type ProseMirrorJSON, type ProseMirrorMark, type ProseMirrorNode, type StructuralChange, type StructuralChangeInfo, type StructuralChangeType, StructuralChangesPane, type StructuralPanePosition, type TrackChangeAuthor, alignDocuments, createTrackDeleteMark, createTrackFormatMark, createTrackInsertMark, DocxDiffEditor as default, detectContentType, diffDocuments, diffImages, diffLists, diffTables, extractEnrichedChanges, extractEnrichedChangesWithStructural, generateFingerprint, generateStructuralChangeSummary, getBlankTemplateBlob, getBlankTemplateFile, isAtomicNode, isImage, isList, isProseMirrorJSON, isTable, isValidDocxFile, mergeDocuments, parseDocxFile, parseHtmlToJson, processStructuralChanges };
848
+ export { type AttrDiff, type AttributeChange, CSS_PREFIX, type ChangeLocation, type CompareWithResult, type ComparisonError, type ComparisonPhase, type ComparisonResult, DEFAULT_AUTHOR, DEFAULT_SUPERDOC_USER, type DiffResult, type DiffSegment, type DocumentInfo, type DocumentProperties, type DocxContent, DocxDiffEditor, type DocxDiffEditorProps, type DocxDiffEditorRef, type EditorError, type EditorOperation, type EnrichedChange, type FingerprintedNode, type FormatChange, type FormatDetails, type HybridDiffResult, type NodeMatch, type ProseMirrorJSON, type ProseMirrorMark, type ProseMirrorNode, type SetSourceError, type StructuralChange, type StructuralChangeInfo, type StructuralChangeType, StructuralChangesPane, type StructuralPanePosition, type TrackChangeAuthor, alignDocuments, createTrackDeleteMark, createTrackFormatMark, createTrackInsertMark, DocxDiffEditor as default, detectContentType, diffDocuments, diffImages, diffLists, diffTables, extractEnrichedChanges, extractEnrichedChangesWithStructural, generateFingerprint, generateStructuralChangeSummary, getBlankTemplateBlob, getBlankTemplateFile, isAtomicNode, isImage, isList, isProseMirrorJSON, isTable, isValidDocxFile, mergeDocuments, parseDocxFile, parseHtmlToJson, processStructuralChanges };
package/dist/index.d.ts CHANGED
@@ -170,9 +170,37 @@ interface StructuralChangeInfo {
170
170
  attrChanges?: AttrDiff[];
171
171
  }
172
172
  /**
173
- * Result returned after comparing two documents
173
+ * Operation types that can fail
174
+ */
175
+ type EditorOperation = 'setSource' | 'compareWith' | 'parseHtml' | 'export' | 'init';
176
+ /**
177
+ * Phase of compareWith where failure occurred
178
+ */
179
+ type ComparisonPhase = 'parsing' | 'diffing' | 'merging' | 'applying';
180
+ /**
181
+ * Enhanced error information passed to onError callback.
182
+ * Provides context about whether the error is recoverable and what operation failed.
183
+ */
184
+ interface EditorError {
185
+ /** The underlying Error object */
186
+ error: Error;
187
+ /** Error classification: 'fatal' means editor is unusable, 'operation' means editor is still functional */
188
+ type: 'fatal' | 'operation';
189
+ /** Which operation failed */
190
+ operation?: EditorOperation;
191
+ /** Whether the editor is still usable after this error */
192
+ recoverable: boolean;
193
+ /** Human-readable error message */
194
+ message: string;
195
+ /** For compareWith: which phase failed */
196
+ phase?: ComparisonPhase;
197
+ }
198
+ /**
199
+ * Successful result returned after comparing two documents
174
200
  */
175
201
  interface ComparisonResult {
202
+ /** Indicates successful comparison */
203
+ success: true;
176
204
  /** Total number of changes */
177
205
  totalChanges: number;
178
206
  /** Number of insertions */
@@ -197,6 +225,25 @@ interface ComparisonResult {
197
225
  */
198
226
  usedFallback?: boolean;
199
227
  }
228
+ /**
229
+ * Failed comparison result.
230
+ * Returned when compareWith fails but the editor is still functional.
231
+ */
232
+ interface ComparisonError {
233
+ /** Indicates failed comparison */
234
+ success: false;
235
+ /** The underlying error */
236
+ error: Error;
237
+ /** Human-readable error message */
238
+ message: string;
239
+ /** Which phase of comparison failed */
240
+ phase: ComparisonPhase;
241
+ }
242
+ /**
243
+ * Union type for compareWith return value.
244
+ * Check the `success` field to determine which type you have.
245
+ */
246
+ type CompareWithResult = ComparisonResult | ComparisonError;
200
247
  /**
201
248
  * Location context for a change
202
249
  */
@@ -326,8 +373,17 @@ interface DocxDiffEditorProps {
326
373
  onSourceLoaded?: (json: ProseMirrorJSON) => void;
327
374
  /** Callback when comparison completes */
328
375
  onComparisonComplete?: (result: ComparisonResult) => void;
329
- /** Callback on errors */
330
- onError?: (error: Error) => void;
376
+ /**
377
+ * Callback on errors.
378
+ *
379
+ * The EditorError object provides context about the error:
380
+ * - `type: 'fatal'` - Editor is unusable (overlay will be shown)
381
+ * - `type: 'operation'` - Operation failed but editor is still functional
382
+ *
383
+ * For operation errors, the editor remains visible and usable.
384
+ * You can use this callback to show a modal or toast notification.
385
+ */
386
+ onError?: (error: EditorError) => void;
331
387
  /** Container className */
332
388
  className?: string;
333
389
  /** Toolbar container className */
@@ -341,16 +397,40 @@ interface DocxDiffEditorProps {
341
397
  /** Hide structural changes pane entirely (default: false) */
342
398
  hideStructuralPane?: boolean;
343
399
  }
400
+ /**
401
+ * Error result for setSource operation
402
+ */
403
+ interface SetSourceError {
404
+ /** Indicates failure */
405
+ success: false;
406
+ /** The underlying error */
407
+ error: Error;
408
+ /** Human-readable error message */
409
+ message: string;
410
+ }
344
411
  /**
345
412
  * Ref methods exposed by DocxDiffEditor
346
413
  */
347
414
  interface DocxDiffEditorRef {
348
- /** Set the source/base document (destroys and recreates SuperDoc instance) */
349
- setSource(content: DocxContent): Promise<void>;
415
+ /**
416
+ * Set the source/base document (destroys and recreates SuperDoc instance).
417
+ *
418
+ * On failure, returns an error object instead of throwing. The editor
419
+ * will attempt to restore the previous state if possible.
420
+ */
421
+ setSource(content: DocxContent): Promise<void | SetSourceError>;
350
422
  /** Update content in the existing editor without recreating SuperDoc instance */
351
423
  updateContent(json: ProseMirrorJSON): void;
352
- /** Compare source with new content, show track changes */
353
- compareWith(content: DocxContent): Promise<ComparisonResult>;
424
+ /**
425
+ * Compare source with new content, show track changes.
426
+ *
427
+ * Returns a union type - check `result.success` to determine outcome:
428
+ * - `success: true` - Comparison succeeded, access result fields
429
+ * - `success: false` - Comparison failed, editor unchanged, check error
430
+ *
431
+ * On failure, the editor is preserved in its previous state.
432
+ */
433
+ compareWith(content: DocxContent): Promise<CompareWithResult>;
354
434
  /** Get raw diff segments */
355
435
  getDiffSegments(): DiffSegment[];
356
436
  /** Get enriched changes with context for LLM processing */
@@ -765,4 +845,4 @@ declare function getBlankTemplateBlob(): Blob;
765
845
  */
766
846
  declare function isValidDocxFile(file: File): boolean;
767
847
 
768
- export { type AttrDiff, type AttributeChange, CSS_PREFIX, type ChangeLocation, type ComparisonResult, DEFAULT_AUTHOR, DEFAULT_SUPERDOC_USER, type DiffResult, type DiffSegment, type DocumentInfo, type DocumentProperties, type DocxContent, DocxDiffEditor, type DocxDiffEditorProps, type DocxDiffEditorRef, type EnrichedChange, type FingerprintedNode, type FormatChange, type FormatDetails, type HybridDiffResult, type NodeMatch, type ProseMirrorJSON, type ProseMirrorMark, type ProseMirrorNode, type StructuralChange, type StructuralChangeInfo, type StructuralChangeType, StructuralChangesPane, type StructuralPanePosition, type TrackChangeAuthor, alignDocuments, createTrackDeleteMark, createTrackFormatMark, createTrackInsertMark, DocxDiffEditor as default, detectContentType, diffDocuments, diffImages, diffLists, diffTables, extractEnrichedChanges, extractEnrichedChangesWithStructural, generateFingerprint, generateStructuralChangeSummary, getBlankTemplateBlob, getBlankTemplateFile, isAtomicNode, isImage, isList, isProseMirrorJSON, isTable, isValidDocxFile, mergeDocuments, parseDocxFile, parseHtmlToJson, processStructuralChanges };
848
+ export { type AttrDiff, type AttributeChange, CSS_PREFIX, type ChangeLocation, type CompareWithResult, type ComparisonError, type ComparisonPhase, type ComparisonResult, DEFAULT_AUTHOR, DEFAULT_SUPERDOC_USER, type DiffResult, type DiffSegment, type DocumentInfo, type DocumentProperties, type DocxContent, DocxDiffEditor, type DocxDiffEditorProps, type DocxDiffEditorRef, type EditorError, type EditorOperation, type EnrichedChange, type FingerprintedNode, type FormatChange, type FormatDetails, type HybridDiffResult, type NodeMatch, type ProseMirrorJSON, type ProseMirrorMark, type ProseMirrorNode, type SetSourceError, type StructuralChange, type StructuralChangeInfo, type StructuralChangeType, StructuralChangesPane, type StructuralPanePosition, type TrackChangeAuthor, alignDocuments, createTrackDeleteMark, createTrackFormatMark, createTrackInsertMark, DocxDiffEditor as default, detectContentType, diffDocuments, diffImages, diffLists, diffTables, extractEnrichedChanges, extractEnrichedChangesWithStructural, generateFingerprint, generateStructuralChangeSummary, getBlankTemplateBlob, getBlankTemplateFile, isAtomicNode, isImage, isList, isProseMirrorJSON, isTable, isValidDocxFile, mergeDocuments, parseDocxFile, parseHtmlToJson, processStructuralChanges };