docx-diff-editor 1.0.7 → 1.0.10

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.mjs CHANGED
@@ -715,6 +715,72 @@ var DocxDiffEditor = forwardRef(
715
715
  }
716
716
  readyRef.current = false;
717
717
  }, []);
718
+ const convertHtmlToDocxBlob = useCallback(
719
+ async (html) => {
720
+ if (!SuperDocRef.current) {
721
+ throw new Error("SuperDoc not loaded");
722
+ }
723
+ const hiddenContainer = document.createElement("div");
724
+ hiddenContainer.id = `dde-hidden-${Date.now()}`;
725
+ hiddenContainer.style.cssText = "position:absolute;top:-9999px;left:-9999px;width:800px;height:600px;visibility:hidden;pointer-events:none;";
726
+ document.body.appendChild(hiddenContainer);
727
+ return new Promise((resolve, reject) => {
728
+ let tempSuperdoc = null;
729
+ let timeoutId;
730
+ const cleanup = () => {
731
+ clearTimeout(timeoutId);
732
+ try {
733
+ tempSuperdoc?.destroy?.();
734
+ } catch {
735
+ }
736
+ hiddenContainer.parentNode?.removeChild(hiddenContainer);
737
+ };
738
+ try {
739
+ tempSuperdoc = new SuperDocRef.current({
740
+ selector: `#${hiddenContainer.id}`,
741
+ html,
742
+ documentMode: "editing",
743
+ rulers: false,
744
+ user: { name: "Converter", email: "converter@local" },
745
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
746
+ onReady: async ({ superdoc: sd }) => {
747
+ try {
748
+ const json = sd?.activeEditor?.getJSON() || { type: "doc", content: [] };
749
+ if (!sd?.activeEditor?.exportDocx) {
750
+ cleanup();
751
+ reject(new Error("exportDocx method not available"));
752
+ return;
753
+ }
754
+ const blob = await sd.activeEditor.exportDocx({ isFinalDoc: false });
755
+ if (!blob) {
756
+ cleanup();
757
+ reject(new Error("Export returned no data"));
758
+ return;
759
+ }
760
+ cleanup();
761
+ resolve({ blob, json });
762
+ } catch (err) {
763
+ cleanup();
764
+ reject(err);
765
+ }
766
+ },
767
+ onException: ({ error: err }) => {
768
+ cleanup();
769
+ reject(err);
770
+ }
771
+ });
772
+ timeoutId = setTimeout(() => {
773
+ cleanup();
774
+ reject(new Error("HTML to DOCX conversion timed out"));
775
+ }, TIMEOUTS.PARSE_TIMEOUT);
776
+ } catch (err) {
777
+ cleanup();
778
+ reject(err);
779
+ }
780
+ });
781
+ },
782
+ []
783
+ );
718
784
  const createSuperdoc = useCallback(
719
785
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
720
786
  async (options) => {
@@ -724,16 +790,31 @@ var DocxDiffEditor = forwardRef(
724
790
  if (!containerRef.current) {
725
791
  throw new Error("Container not available");
726
792
  }
793
+ containerRef.current.innerHTML = "";
794
+ if (toolbarRef.current) {
795
+ toolbarRef.current.innerHTML = "";
796
+ }
727
797
  containerRef.current.id = editorId;
728
798
  if (toolbarRef.current) {
729
799
  toolbarRef.current.id = toolbarId;
730
800
  }
801
+ let documentFile;
802
+ if (options.document) {
803
+ if (options.document instanceof File) {
804
+ documentFile = options.document;
805
+ } else {
806
+ documentFile = new File([options.document], "document.docx", {
807
+ type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
808
+ });
809
+ }
810
+ }
731
811
  return new Promise((resolve, reject) => {
812
+ let resolved = false;
732
813
  try {
733
814
  const superdoc = new SuperDocRef.current({
734
815
  selector: `#${editorId}`,
735
816
  toolbar: showToolbar ? `#${toolbarId}` : void 0,
736
- document: options.document,
817
+ document: documentFile,
737
818
  html: options.html,
738
819
  documentMode: "editing",
739
820
  role: "editor",
@@ -743,6 +824,8 @@ var DocxDiffEditor = forwardRef(
743
824
  // Enable comments module for track changes sidebar
744
825
  modules: { comments: {} },
745
826
  onReady: ({ superdoc: sd }) => {
827
+ if (resolved) return;
828
+ resolved = true;
746
829
  superdocRef.current = sd;
747
830
  readyRef.current = true;
748
831
  let json = { type: "doc", content: [] };
@@ -756,18 +839,24 @@ var DocxDiffEditor = forwardRef(
756
839
  resolve({ superdoc: sd, json });
757
840
  },
758
841
  onException: ({ error: err }) => {
842
+ if (resolved) return;
843
+ resolved = true;
759
844
  console.error("SuperDoc error:", err);
760
845
  reject(err);
761
846
  }
762
847
  });
763
848
  superdocRef.current = superdoc;
764
849
  setTimeout(() => {
765
- if (!readyRef.current) {
850
+ if (!resolved) {
851
+ resolved = true;
766
852
  reject(new Error("SuperDoc initialization timed out"));
767
853
  }
768
854
  }, TIMEOUTS.PARSE_TIMEOUT);
769
855
  } catch (err) {
770
- reject(err);
856
+ if (!resolved) {
857
+ resolved = true;
858
+ reject(err);
859
+ }
771
860
  }
772
861
  });
773
862
  },
@@ -791,12 +880,15 @@ var DocxDiffEditor = forwardRef(
791
880
  const { SuperDoc } = await import('superdoc');
792
881
  SuperDocRef.current = SuperDoc;
793
882
  let initOptions = {};
883
+ let extractedJson = null;
794
884
  if (initialSource) {
795
885
  const contentType = detectContentType(initialSource);
796
886
  if (contentType === "file") {
797
887
  initOptions = { document: initialSource };
798
888
  } else if (contentType === "html") {
799
- initOptions = { html: initialSource };
889
+ const { blob, json: htmlJson } = await convertHtmlToDocxBlob(initialSource);
890
+ initOptions = { document: blob };
891
+ extractedJson = htmlJson;
800
892
  } else if (contentType === "json") {
801
893
  initOptions = templateDocx ? { document: templateDocx } : {};
802
894
  }
@@ -811,8 +903,9 @@ var DocxDiffEditor = forwardRef(
811
903
  onSourceLoaded?.(initialSource);
812
904
  }
813
905
  } else {
814
- setSourceJson(json);
815
- onSourceLoaded?.(json);
906
+ const finalJson = extractedJson || json;
907
+ setSourceJson(finalJson);
908
+ onSourceLoaded?.(finalJson);
816
909
  }
817
910
  setIsLoading(false);
818
911
  onReady?.();
@@ -831,6 +924,7 @@ var DocxDiffEditor = forwardRef(
831
924
  onSourceLoaded,
832
925
  destroySuperdoc,
833
926
  createSuperdoc,
927
+ convertHtmlToDocxBlob,
834
928
  setEditorContent,
835
929
  handleError
836
930
  ]);
@@ -846,7 +940,11 @@ var DocxDiffEditor = forwardRef(
846
940
  ref,
847
941
  () => ({
848
942
  /**
849
- * Set the source/base document
943
+ * Set the source/base document.
944
+ *
945
+ * For HTML content, we convert to DOCX first using a hidden SuperDoc instance.
946
+ * This is critical because SuperDoc's track change infrastructure (including
947
+ * track bubbles) is only properly initialized when loading from a DOCX file.
850
948
  */
851
949
  async setSource(content) {
852
950
  if (!SuperDocRef.current) {
@@ -862,8 +960,15 @@ var DocxDiffEditor = forwardRef(
862
960
  const result = await createSuperdoc({ document: content });
863
961
  json = result.json;
864
962
  } else if (contentType === "html") {
865
- const result = await createSuperdoc({ html: content });
866
- json = result.json;
963
+ const { blob, json: extractedJson } = await convertHtmlToDocxBlob(content);
964
+ const result = await createSuperdoc({ document: blob });
965
+ json = extractedJson;
966
+ if (result.superdoc?.activeEditor) {
967
+ const editorJson = result.superdoc.activeEditor.getJSON();
968
+ if (!extractedJson.content || extractedJson.content.length === 0) {
969
+ json = editorJson;
970
+ }
971
+ }
867
972
  } else {
868
973
  const result = await createSuperdoc(templateDocx ? { document: templateDocx } : {});
869
974
  if (result.superdoc?.activeEditor && isProseMirrorJSON(content)) {
@@ -1050,6 +1155,7 @@ var DocxDiffEditor = forwardRef(
1050
1155
  author,
1051
1156
  destroySuperdoc,
1052
1157
  createSuperdoc,
1158
+ convertHtmlToDocxBlob,
1053
1159
  setEditorContent,
1054
1160
  enableReviewMode,
1055
1161
  setEditingMode,