docx-diff-editor 1.0.43 → 1.0.45

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
@@ -257,13 +257,19 @@ await editorRef.current?.setProperties({
257
257
 
258
258
  ## Parsing HTML to JSON
259
259
 
260
- Convert HTML strings to ProseMirror JSON without visible rendering:
260
+ Convert HTML strings to ProseMirror JSON without visible rendering. **Inline styles are preserved!**
261
261
 
262
262
  ```tsx
263
263
  // Using the ref method (requires editor to be initialized)
264
264
  const json = await editorRef.current?.parseHtml('<h1>Title</h1><p>Content here</p>');
265
265
  console.log(json); // { type: 'doc', content: [...] }
266
266
 
267
+ // Inline styles are converted to marks
268
+ const styledJson = await editorRef.current?.parseHtml(
269
+ '<p><span style="color: red; font-weight: bold;">styled text</span></p>'
270
+ );
271
+ // Result: text with textStyle mark (color) and bold mark
272
+
267
273
  // Use with other methods
268
274
  await editorRef.current?.updateContent(json);
269
275
 
@@ -272,6 +278,19 @@ import { parseHtmlToJson } from 'docx-diff-editor';
272
278
  const json = await parseHtmlToJson(htmlString, SuperDocClass);
273
279
  ```
274
280
 
281
+ ### Supported Inline Styles
282
+
283
+ | CSS Property | ProseMirror Mark |
284
+ |--------------|------------------|
285
+ | `color` | `textStyle.color` |
286
+ | `font-size` | `textStyle.fontSize` |
287
+ | `font-family` | `textStyle.fontFamily` |
288
+ | `font-weight: bold` | `bold` |
289
+ | `font-style: italic` | `italic` |
290
+ | `text-decoration: underline` | `underline` |
291
+ | `text-decoration: line-through` | `strike` |
292
+ | `background-color` | `highlight.color` |
293
+
275
294
  ## Customization
276
295
 
277
296
  ### CSS Variables
package/dist/index.d.mts CHANGED
@@ -424,6 +424,20 @@ declare function detectContentType(content: DocxContent): 'file' | 'html' | 'jso
424
424
  declare function isProseMirrorJSON(content: unknown): boolean;
425
425
  /**
426
426
  * Parse an HTML string into ProseMirror JSON using a hidden SuperDoc instance.
427
+ *
428
+ * IMPORTANT: Uses the "paste" approach instead of the "import" approach.
429
+ * SuperDoc's import path (via `html` option) calls `stripHtmlStyles()` which
430
+ * removes all CSS styles except `text-align`. The paste path (via `view.pasteHTML()`)
431
+ * preserves inline styles like color, font-size, font-family, font-weight, etc.
432
+ *
433
+ * Flow:
434
+ * 1. Create SuperDoc with empty HTML document
435
+ * 2. Wait for editor to be ready
436
+ * 3. Select all content and delete it (start fresh)
437
+ * 4. Use editor.view.pasteHTML(html) - this uses the paste path which preserves styles
438
+ * 5. Return the resulting JSON
439
+ *
440
+ * Falls back to the standard import approach if paste fails.
427
441
  */
428
442
  declare function parseHtmlToJson(html: string, SuperDoc: SuperDocConstructor): Promise<ProseMirrorJSON>;
429
443
  /**
package/dist/index.d.ts CHANGED
@@ -424,6 +424,20 @@ declare function detectContentType(content: DocxContent): 'file' | 'html' | 'jso
424
424
  declare function isProseMirrorJSON(content: unknown): boolean;
425
425
  /**
426
426
  * Parse an HTML string into ProseMirror JSON using a hidden SuperDoc instance.
427
+ *
428
+ * IMPORTANT: Uses the "paste" approach instead of the "import" approach.
429
+ * SuperDoc's import path (via `html` option) calls `stripHtmlStyles()` which
430
+ * removes all CSS styles except `text-align`. The paste path (via `view.pasteHTML()`)
431
+ * preserves inline styles like color, font-size, font-family, font-weight, etc.
432
+ *
433
+ * Flow:
434
+ * 1. Create SuperDoc with empty HTML document
435
+ * 2. Wait for editor to be ready
436
+ * 3. Select all content and delete it (start fresh)
437
+ * 4. Use editor.view.pasteHTML(html) - this uses the paste path which preserves styles
438
+ * 5. Return the resulting JSON
439
+ *
440
+ * Falls back to the standard import approach if paste fails.
427
441
  */
428
442
  declare function parseHtmlToJson(html: string, SuperDoc: SuperDocConstructor): Promise<ProseMirrorJSON>;
429
443
  /**
package/dist/index.js CHANGED
@@ -490,38 +490,124 @@ async function parseHtmlToJson(html, SuperDoc) {
490
490
  }
491
491
  }, TIMEOUTS.CLEANUP_DELAY);
492
492
  };
493
+ const createMockPasteEvent = (htmlContent) => {
494
+ const dataTransfer = new DataTransfer();
495
+ dataTransfer.setData("text/html", htmlContent);
496
+ dataTransfer.setData("text/plain", "");
497
+ const event = new ClipboardEvent("paste", {
498
+ bubbles: true,
499
+ cancelable: true,
500
+ clipboardData: dataTransfer
501
+ });
502
+ return event;
503
+ };
504
+ const tryPasteApproach = (sd, onSuccess, onFail) => {
505
+ try {
506
+ const editor = sd?.activeEditor;
507
+ if (!editor?.view?.pasteHTML) {
508
+ onFail();
509
+ return;
510
+ }
511
+ editor.commands.focus?.();
512
+ if (editor.commands.selectAll && editor.commands.deleteSelection) {
513
+ editor.commands.selectAll();
514
+ editor.commands.deleteSelection();
515
+ }
516
+ const mockEvent = createMockPasteEvent(html);
517
+ editor.view.pasteHTML(html, mockEvent);
518
+ setTimeout(() => {
519
+ try {
520
+ const json = editor.getJSON();
521
+ if (json?.content?.length > 0) {
522
+ onSuccess(json);
523
+ } else {
524
+ onFail();
525
+ }
526
+ } catch {
527
+ onFail();
528
+ }
529
+ }, 100);
530
+ } catch (err) {
531
+ console.warn("[parseHtmlToJson] Paste approach error:", err);
532
+ onFail();
533
+ }
534
+ };
535
+ const fallbackToImport = () => {
536
+ if (superdoc) {
537
+ try {
538
+ superdoc.destroy?.();
539
+ } catch {
540
+ }
541
+ superdoc = null;
542
+ }
543
+ superdoc = new SuperDoc({
544
+ selector: container,
545
+ html,
546
+ // Use the actual HTML content
547
+ documentMode: "viewing",
548
+ rulers: false,
549
+ user: { name: "Parser", email: "parser@local" },
550
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
551
+ onReady: ({ superdoc: sd }) => {
552
+ if (resolved) return;
553
+ try {
554
+ const editor = sd?.activeEditor;
555
+ if (!editor) {
556
+ throw new Error("No active editor found");
557
+ }
558
+ const json = editor.getJSON();
559
+ resolved = true;
560
+ cleanup();
561
+ resolve(json);
562
+ } catch (err) {
563
+ resolved = true;
564
+ cleanup();
565
+ reject(err);
566
+ }
567
+ },
568
+ onException: ({ error: err }) => {
569
+ if (resolved) return;
570
+ resolved = true;
571
+ cleanup();
572
+ reject(err);
573
+ }
574
+ });
575
+ };
493
576
  setTimeout(async () => {
494
577
  if (resolved) return;
495
578
  try {
496
579
  superdoc = new SuperDoc({
497
580
  selector: container,
498
- html,
499
- documentMode: "viewing",
581
+ html: "<p></p>",
582
+ // Minimal empty document
583
+ documentMode: "editing",
584
+ // Need editing mode to use paste
500
585
  rulers: false,
501
586
  user: { name: "Parser", email: "parser@local" },
502
587
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
503
588
  onReady: ({ superdoc: sd }) => {
504
589
  if (resolved) return;
505
- try {
506
- const editor = sd?.activeEditor;
507
- if (!editor) {
508
- throw new Error("No active editor found");
590
+ tryPasteApproach(
591
+ sd,
592
+ // Success callback
593
+ (json) => {
594
+ if (resolved) return;
595
+ resolved = true;
596
+ cleanup();
597
+ resolve(json);
598
+ },
599
+ // Fail callback - try fallback
600
+ () => {
601
+ if (resolved) return;
602
+ console.warn("[parseHtmlToJson] Paste approach failed, falling back to import");
603
+ fallbackToImport();
509
604
  }
510
- const json = editor.getJSON();
511
- resolved = true;
512
- cleanup();
513
- resolve(json);
514
- } catch (err) {
515
- resolved = true;
516
- cleanup();
517
- reject(err);
518
- }
605
+ );
519
606
  },
520
607
  onException: ({ error: err }) => {
521
608
  if (resolved) return;
522
- resolved = true;
523
- cleanup();
524
- reject(err);
609
+ console.warn("[parseHtmlToJson] Paste approach exception, falling back:", err);
610
+ fallbackToImport();
525
611
  }
526
612
  });
527
613
  setTimeout(() => {
@@ -532,8 +618,12 @@ async function parseHtmlToJson(html, SuperDoc) {
532
618
  }
533
619
  }, TIMEOUTS.PARSE_TIMEOUT);
534
620
  } catch (err) {
535
- cleanup();
536
- reject(err);
621
+ try {
622
+ fallbackToImport();
623
+ } catch (fallbackErr) {
624
+ cleanup();
625
+ reject(fallbackErr);
626
+ }
537
627
  }
538
628
  }, 50);
539
629
  });