docx-diff-editor 1.0.9 → 1.0.14

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/dist/index.js CHANGED
@@ -723,6 +723,74 @@ var DocxDiffEditor = react.forwardRef(
723
723
  }
724
724
  readyRef.current = false;
725
725
  }, []);
726
+ const convertHtmlToDocxBlob = react.useCallback(
727
+ async (html) => {
728
+ if (!SuperDocRef.current) {
729
+ throw new Error("SuperDoc not loaded");
730
+ }
731
+ const hiddenContainer = document.createElement("div");
732
+ hiddenContainer.id = `dde-hidden-${Date.now()}`;
733
+ hiddenContainer.style.cssText = "position:absolute;top:-9999px;left:-9999px;width:800px;height:600px;visibility:hidden;pointer-events:none;";
734
+ document.body.appendChild(hiddenContainer);
735
+ return new Promise((resolve, reject) => {
736
+ let resolved = false;
737
+ let tempSuperdoc = null;
738
+ const cleanup = () => {
739
+ try {
740
+ tempSuperdoc?.destroy?.();
741
+ } catch {
742
+ }
743
+ hiddenContainer.parentNode?.removeChild(hiddenContainer);
744
+ };
745
+ try {
746
+ tempSuperdoc = new SuperDocRef.current({
747
+ selector: `#${hiddenContainer.id}`,
748
+ html,
749
+ documentMode: "editing",
750
+ rulers: false,
751
+ user: { name: "Converter", email: "converter@local" },
752
+ onReady: async ({ superdoc: sd }) => {
753
+ if (resolved) return;
754
+ try {
755
+ const json = sd?.activeEditor?.getJSON() || { type: "doc", content: [] };
756
+ const blob = await sd?.activeEditor?.exportDocx({ isFinalDoc: true });
757
+ if (!blob) {
758
+ throw new Error("Export returned no data");
759
+ }
760
+ resolved = true;
761
+ cleanup();
762
+ resolve({ blob, json });
763
+ } catch (err) {
764
+ resolved = true;
765
+ cleanup();
766
+ reject(err);
767
+ }
768
+ },
769
+ onException: ({ error: err }) => {
770
+ if (resolved) return;
771
+ resolved = true;
772
+ cleanup();
773
+ reject(err);
774
+ }
775
+ });
776
+ setTimeout(() => {
777
+ if (!resolved) {
778
+ resolved = true;
779
+ cleanup();
780
+ reject(new Error("HTML to DOCX conversion timed out"));
781
+ }
782
+ }, TIMEOUTS.PARSE_TIMEOUT);
783
+ } catch (err) {
784
+ if (!resolved) {
785
+ resolved = true;
786
+ cleanup();
787
+ reject(err);
788
+ }
789
+ }
790
+ });
791
+ },
792
+ []
793
+ );
726
794
  const createSuperdoc = react.useCallback(
727
795
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
728
796
  async (options) => {
@@ -732,25 +800,29 @@ var DocxDiffEditor = react.forwardRef(
732
800
  if (!containerRef.current) {
733
801
  throw new Error("Container not available");
734
802
  }
803
+ containerRef.current.innerHTML = "";
804
+ if (toolbarRef.current) {
805
+ toolbarRef.current.innerHTML = "";
806
+ }
735
807
  containerRef.current.id = editorId;
736
808
  if (toolbarRef.current) {
737
809
  toolbarRef.current.id = toolbarId;
738
810
  }
739
811
  return new Promise((resolve, reject) => {
812
+ let resolved = false;
740
813
  try {
741
814
  const superdoc = new SuperDocRef.current({
742
815
  selector: `#${editorId}`,
743
816
  toolbar: showToolbar ? `#${toolbarId}` : void 0,
744
817
  document: options.document,
745
- html: options.html,
746
818
  documentMode: "editing",
747
819
  role: "editor",
748
820
  rulers: showRulers,
749
821
  user: DEFAULT_SUPERDOC_USER,
750
822
  permissionResolver,
751
- // Enable comments module for track changes sidebar
752
- modules: { comments: {} },
753
823
  onReady: ({ superdoc: sd }) => {
824
+ if (resolved) return;
825
+ resolved = true;
754
826
  superdocRef.current = sd;
755
827
  readyRef.current = true;
756
828
  let json = { type: "doc", content: [] };
@@ -764,18 +836,24 @@ var DocxDiffEditor = react.forwardRef(
764
836
  resolve({ superdoc: sd, json });
765
837
  },
766
838
  onException: ({ error: err }) => {
839
+ if (resolved) return;
840
+ resolved = true;
767
841
  console.error("SuperDoc error:", err);
768
842
  reject(err);
769
843
  }
770
844
  });
771
845
  superdocRef.current = superdoc;
772
846
  setTimeout(() => {
773
- if (!readyRef.current) {
847
+ if (!resolved) {
848
+ resolved = true;
774
849
  reject(new Error("SuperDoc initialization timed out"));
775
850
  }
776
851
  }, TIMEOUTS.PARSE_TIMEOUT);
777
852
  } catch (err) {
778
- reject(err);
853
+ if (!resolved) {
854
+ resolved = true;
855
+ reject(err);
856
+ }
779
857
  }
780
858
  });
781
859
  },
@@ -799,12 +877,15 @@ var DocxDiffEditor = react.forwardRef(
799
877
  const { SuperDoc } = await import('superdoc');
800
878
  SuperDocRef.current = SuperDoc;
801
879
  let initOptions = {};
880
+ let extractedJson = null;
802
881
  if (initialSource) {
803
882
  const contentType = detectContentType(initialSource);
804
883
  if (contentType === "file") {
805
884
  initOptions = { document: initialSource };
806
885
  } else if (contentType === "html") {
807
- initOptions = { html: initialSource };
886
+ const { blob, json: htmlJson } = await convertHtmlToDocxBlob(initialSource);
887
+ initOptions = { document: blob };
888
+ extractedJson = htmlJson;
808
889
  } else if (contentType === "json") {
809
890
  initOptions = templateDocx ? { document: templateDocx } : {};
810
891
  }
@@ -819,8 +900,9 @@ var DocxDiffEditor = react.forwardRef(
819
900
  onSourceLoaded?.(initialSource);
820
901
  }
821
902
  } else {
822
- setSourceJson(json);
823
- onSourceLoaded?.(json);
903
+ const sourceJsonToUse = extractedJson || json;
904
+ setSourceJson(sourceJsonToUse);
905
+ onSourceLoaded?.(sourceJsonToUse);
824
906
  }
825
907
  setIsLoading(false);
826
908
  onReady?.();
@@ -839,6 +921,7 @@ var DocxDiffEditor = react.forwardRef(
839
921
  onSourceLoaded,
840
922
  destroySuperdoc,
841
923
  createSuperdoc,
924
+ convertHtmlToDocxBlob,
842
925
  setEditorContent,
843
926
  handleError
844
927
  ]);
@@ -854,7 +937,10 @@ var DocxDiffEditor = react.forwardRef(
854
937
  ref,
855
938
  () => ({
856
939
  /**
857
- * Set the source/base document
940
+ * Set the source/base document.
941
+ *
942
+ * IMPORTANT: For HTML content, we convert to DOCX first using a hidden
943
+ * SuperDoc instance. This is required for track bubbles to work properly.
858
944
  */
859
945
  async setSource(content) {
860
946
  if (!SuperDocRef.current) {
@@ -870,8 +956,9 @@ var DocxDiffEditor = react.forwardRef(
870
956
  const result = await createSuperdoc({ document: content });
871
957
  json = result.json;
872
958
  } else if (contentType === "html") {
873
- const result = await createSuperdoc({ html: content });
874
- json = result.json;
959
+ const { blob, json: htmlJson } = await convertHtmlToDocxBlob(content);
960
+ const result = await createSuperdoc({ document: blob });
961
+ json = htmlJson;
875
962
  } else {
876
963
  const result = await createSuperdoc(templateDocx ? { document: templateDocx } : {});
877
964
  if (result.superdoc?.activeEditor && isProseMirrorJSON(content)) {
@@ -966,11 +1053,24 @@ var DocxDiffEditor = react.forwardRef(
966
1053
  const merged = mergeDocuments(sourceJson, newJson, diff, author);
967
1054
  setMergedJson(merged);
968
1055
  if (superdocRef.current?.activeEditor) {
969
- if (superdocRef.current.setDocumentMode) {
970
- superdocRef.current.setDocumentMode("suggesting");
971
- }
972
1056
  setEditorContent(superdocRef.current.activeEditor, merged);
973
1057
  enableReviewMode(superdocRef.current);
1058
+ const sd = superdocRef.current;
1059
+ if (sd.commentsStore?.processLoadedDocxComments) {
1060
+ setTimeout(() => {
1061
+ try {
1062
+ sd.commentsStore.processLoadedDocxComments({
1063
+ superdoc: sd,
1064
+ editor: sd.activeEditor,
1065
+ comments: [],
1066
+ // Empty array - we just want to trigger createCommentForTrackChanges
1067
+ documentId: sd.activeEditor?.options?.documentId || "primary"
1068
+ });
1069
+ } catch (err) {
1070
+ console.warn("[DocxDiffEditor] Failed to process track changes for bubbles:", err);
1071
+ }
1072
+ }, 50);
1073
+ }
974
1074
  }
975
1075
  const insertions = diff.segments.filter((s) => s.type === "insert").length;
976
1076
  const deletions = diff.segments.filter((s) => s.type === "delete").length;
@@ -1061,6 +1161,7 @@ var DocxDiffEditor = react.forwardRef(
1061
1161
  author,
1062
1162
  destroySuperdoc,
1063
1163
  createSuperdoc,
1164
+ convertHtmlToDocxBlob,
1064
1165
  setEditorContent,
1065
1166
  enableReviewMode,
1066
1167
  setEditingMode,