@baasix/lexical 0.0.3 → 0.0.5

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
@@ -34,7 +34,7 @@ import {
34
34
  ExcalidrawModal,
35
35
  ExcalidrawNode,
36
36
  Modal
37
- } from "./chunk-N22RKA5D.js";
37
+ } from "./chunk-RIV43XYA.js";
38
38
  import {
39
39
  $createPollNode,
40
40
  PollNode,
@@ -67,7 +67,7 @@ import { LexicalComposer as LexicalComposer2 } from "@lexical/react/LexicalCompo
67
67
  import { OnChangePlugin as OnChangePlugin2 } from "@lexical/react/LexicalOnChangePlugin";
68
68
  import { useLexicalComposerContext as useLexicalComposerContext46 } from "@lexical/react/LexicalComposerContext";
69
69
  import { $generateHtmlFromNodes, $generateNodesFromDOM } from "@lexical/html";
70
- import { $getRoot as $getRoot3, $insertNodes as $insertNodes6 } from "lexical";
70
+ import { $getRoot as $getRoot3, $insertNodes as $insertNodes6, $setSelection as $setSelection7 } from "lexical";
71
71
 
72
72
  // src/Editor.tsx
73
73
  import { CharacterLimitPlugin } from "@lexical/react/LexicalCharacterLimitPlugin";
@@ -102,7 +102,8 @@ import {
102
102
  $getRoot,
103
103
  $isParagraphNode as $isParagraphNode2,
104
104
  CLEAR_EDITOR_COMMAND,
105
- HISTORIC_TAG
105
+ HISTORIC_TAG,
106
+ SELECTION_CHANGE_COMMAND
106
107
  } from "lexical";
107
108
  import { useCallback as useCallback4, useEffect as useEffect4, useState as useState4 } from "react";
108
109
 
@@ -752,6 +753,8 @@ function ActionsPlugin({
752
753
  const [isEditable, setIsEditable] = useState4(() => editor.isEditable());
753
754
  const [isSpeechToText, setIsSpeechToText] = useState4(false);
754
755
  const [isEditorEmpty, setIsEditorEmpty] = useState4(true);
756
+ const [isConverting, setIsConverting] = useState4(false);
757
+ const [isMarkdown, setIsMarkdown] = useState4(false);
755
758
  const [modal, showModal] = useModal();
756
759
  const { isFullscreen, toggleFullscreen } = useFullscreen();
757
760
  useEffect4(() => {
@@ -770,11 +773,15 @@ function ActionsPlugin({
770
773
  editor.getEditorState().read(() => {
771
774
  const root = $getRoot();
772
775
  const children = root.getChildren();
776
+ const firstChild = children[0];
777
+ setIsMarkdown(
778
+ children.length === 1 && $isCodeNode(firstChild) && firstChild.getLanguage() === "markdown"
779
+ );
773
780
  if (children.length > 1) {
774
781
  setIsEditorEmpty(false);
775
782
  } else {
776
- if ($isParagraphNode2(children[0])) {
777
- const paragraphChildren = children[0].getChildren();
783
+ if ($isParagraphNode2(firstChild)) {
784
+ const paragraphChildren = firstChild.getChildren();
778
785
  setIsEditorEmpty(paragraphChildren.length === 0);
779
786
  } else {
780
787
  setIsEditorEmpty(false);
@@ -785,32 +792,73 @@ function ActionsPlugin({
785
792
  );
786
793
  }, [editor, isEditable]);
787
794
  const handleMarkdownToggle = useCallback4(() => {
788
- editor.update(() => {
795
+ if (isConverting) return;
796
+ const currentlyMarkdown = editor.getEditorState().read(() => {
789
797
  const root = $getRoot();
790
798
  const firstChild = root.getFirstChild();
791
- if ($isCodeNode(firstChild) && firstChild.getLanguage() === "markdown") {
792
- $convertFromMarkdownString2(
793
- firstChild.getTextContent(),
794
- PLAYGROUND_TRANSFORMERS,
795
- void 0,
796
- // node
797
- shouldPreserveNewLinesInMarkdown
798
- );
799
- root.selectEnd();
800
- } else {
801
- const markdown = $convertToMarkdownString2(
802
- PLAYGROUND_TRANSFORMERS,
803
- void 0,
804
- //node
805
- shouldPreserveNewLinesInMarkdown
806
- );
807
- const codeNode = $createCodeNode("markdown");
808
- codeNode.append($createTextNode2(markdown));
809
- root.clear().append(codeNode);
810
- codeNode.select();
811
- }
799
+ return $isCodeNode(firstChild) && firstChild.getLanguage() === "markdown";
812
800
  });
813
- }, [editor, shouldPreserveNewLinesInMarkdown]);
801
+ if (currentlyMarkdown) {
802
+ setIsConverting(true);
803
+ requestAnimationFrame(() => {
804
+ requestAnimationFrame(() => {
805
+ try {
806
+ const markdownText = editor.getEditorState().read(() => {
807
+ const root = $getRoot();
808
+ const firstChild = root.getFirstChild();
809
+ return $isCodeNode(firstChild) ? firstChild.getTextContent() : "";
810
+ });
811
+ editor.update(
812
+ () => {
813
+ const root = $getRoot();
814
+ root.clear();
815
+ $convertFromMarkdownString2(
816
+ markdownText,
817
+ PLAYGROUND_TRANSFORMERS,
818
+ void 0,
819
+ // operate on $getRoot()
820
+ shouldPreserveNewLinesInMarkdown
821
+ );
822
+ $getRoot().selectEnd();
823
+ },
824
+ { tag: "historic" }
825
+ );
826
+ editor.dispatchCommand(SELECTION_CHANGE_COMMAND, void 0);
827
+ } finally {
828
+ setIsConverting(false);
829
+ }
830
+ });
831
+ });
832
+ } else {
833
+ setIsConverting(true);
834
+ requestAnimationFrame(() => {
835
+ requestAnimationFrame(() => {
836
+ try {
837
+ const markdown = editor.getEditorState().read(
838
+ () => $convertToMarkdownString2(
839
+ PLAYGROUND_TRANSFORMERS,
840
+ void 0,
841
+ shouldPreserveNewLinesInMarkdown
842
+ )
843
+ );
844
+ editor.update(
845
+ () => {
846
+ const root = $getRoot();
847
+ const codeNode = $createCodeNode("markdown");
848
+ codeNode.append($createTextNode2(markdown));
849
+ root.clear().append(codeNode);
850
+ codeNode.select();
851
+ },
852
+ { tag: "historic" }
853
+ );
854
+ editor.dispatchCommand(SELECTION_CHANGE_COMMAND, void 0);
855
+ } finally {
856
+ setIsConverting(false);
857
+ }
858
+ });
859
+ });
860
+ }
861
+ }, [editor, shouldPreserveNewLinesInMarkdown, isConverting]);
814
862
  return /* @__PURE__ */ jsxs2("div", { className: "actions", children: [
815
863
  /* @__PURE__ */ jsx3(
816
864
  "button",
@@ -871,11 +919,11 @@ function ActionsPlugin({
871
919
  "button",
872
920
  {
873
921
  type: "button",
874
- className: "action-button",
922
+ className: `action-button ${isMarkdown ? "active" : ""}`,
875
923
  onClick: handleMarkdownToggle,
876
- title: "Convert From Markdown",
877
- "aria-label": "Convert from markdown",
878
- children: /* @__PURE__ */ jsx3("i", { className: "markdown" })
924
+ title: isMarkdown ? "Convert to Rich Text" : "Convert to Markdown",
925
+ "aria-label": isMarkdown ? "Convert to rich text" : "Convert to markdown",
926
+ children: isConverting ? /* @__PURE__ */ jsx3("span", { className: "action-button-spinner" }) : /* @__PURE__ */ jsx3("i", { className: "markdown" })
879
927
  }
880
928
  ),
881
929
  modal
@@ -9832,7 +9880,7 @@ import {
9832
9880
  COMMAND_PRIORITY_LOW as COMMAND_PRIORITY_LOW8,
9833
9881
  getDOMSelection as getDOMSelection2,
9834
9882
  KEY_ESCAPE_COMMAND as KEY_ESCAPE_COMMAND2,
9835
- SELECTION_CHANGE_COMMAND
9883
+ SELECTION_CHANGE_COMMAND as SELECTION_CHANGE_COMMAND2
9836
9884
  } from "lexical";
9837
9885
  import { useCallback as useCallback20, useEffect as useEffect31, useRef as useRef10, useState as useState28 } from "react";
9838
9886
  import { createPortal as createPortal8 } from "react-dom";
@@ -9995,7 +10043,7 @@ function FloatingLinkEditor({
9995
10043
  });
9996
10044
  }),
9997
10045
  editor.registerCommand(
9998
- SELECTION_CHANGE_COMMAND,
10046
+ SELECTION_CHANGE_COMMAND2,
9999
10047
  () => {
10000
10048
  $updateLinkEditor();
10001
10049
  return true;
@@ -10202,7 +10250,7 @@ function useFloatingLinkEditorToolbar(editor, anchorElem, isLinkEditMode, setIsL
10202
10250
  });
10203
10251
  }),
10204
10252
  editor.registerCommand(
10205
- SELECTION_CHANGE_COMMAND,
10253
+ SELECTION_CHANGE_COMMAND2,
10206
10254
  (_payload, newEditor) => {
10207
10255
  $updateToolbar();
10208
10256
  setActiveEditor(newEditor);
@@ -10270,7 +10318,7 @@ import {
10270
10318
  COMMAND_PRIORITY_LOW as COMMAND_PRIORITY_LOW9,
10271
10319
  FORMAT_TEXT_COMMAND,
10272
10320
  getDOMSelection as getDOMSelection3,
10273
- SELECTION_CHANGE_COMMAND as SELECTION_CHANGE_COMMAND2
10321
+ SELECTION_CHANGE_COMMAND as SELECTION_CHANGE_COMMAND3
10274
10322
  } from "lexical";
10275
10323
  import { useCallback as useCallback21, useEffect as useEffect32, useRef as useRef11, useState as useState29 } from "react";
10276
10324
  import { createPortal as createPortal9 } from "react-dom";
@@ -10440,7 +10488,7 @@ function TextFormatFloatingToolbar({
10440
10488
  });
10441
10489
  }),
10442
10490
  editor.registerCommand(
10443
- SELECTION_CHANGE_COMMAND2,
10491
+ SELECTION_CHANGE_COMMAND3,
10444
10492
  () => {
10445
10493
  $updateTextFormatFloatingToolbar();
10446
10494
  return false;
@@ -11493,7 +11541,7 @@ import {
11493
11541
  COMMAND_PRIORITY_CRITICAL as COMMAND_PRIORITY_CRITICAL2,
11494
11542
  getDOMSelection as getDOMSelection4,
11495
11543
  isDOMNode as isDOMNode2,
11496
- SELECTION_CHANGE_COMMAND as SELECTION_CHANGE_COMMAND3
11544
+ SELECTION_CHANGE_COMMAND as SELECTION_CHANGE_COMMAND4
11497
11545
  } from "lexical";
11498
11546
  import { useCallback as useCallback22, useEffect as useEffect37, useRef as useRef13, useState as useState31 } from "react";
11499
11547
  import { createPortal as createPortal10 } from "react-dom";
@@ -12500,7 +12548,7 @@ function TableCellActionMenuContainer({
12500
12548
  return mergeRegister12(
12501
12549
  editor.registerUpdateListener(delayedCallback),
12502
12550
  editor.registerCommand(
12503
- SELECTION_CHANGE_COMMAND3,
12551
+ SELECTION_CHANGE_COMMAND4,
12504
12552
  delayedCallback,
12505
12553
  COMMAND_PRIORITY_CRITICAL2
12506
12554
  ),
@@ -13830,7 +13878,7 @@ import {
13830
13878
  INDENT_CONTENT_COMMAND as INDENT_CONTENT_COMMAND2,
13831
13879
  OUTDENT_CONTENT_COMMAND as OUTDENT_CONTENT_COMMAND2,
13832
13880
  REDO_COMMAND as REDO_COMMAND2,
13833
- SELECTION_CHANGE_COMMAND as SELECTION_CHANGE_COMMAND4,
13881
+ SELECTION_CHANGE_COMMAND as SELECTION_CHANGE_COMMAND5,
13834
13882
  SKIP_DOM_SELECTION_TAG as SKIP_DOM_SELECTION_TAG2,
13835
13883
  SKIP_SELECTION_FOCUS_TAG as SKIP_SELECTION_FOCUS_TAG2,
13836
13884
  UNDO_COMMAND as UNDO_COMMAND2
@@ -14515,8 +14563,9 @@ function ToolbarPlugin({
14515
14563
  );
14516
14564
  const theme2 = element.getTheme();
14517
14565
  updateToolbarState("codeTheme", theme2 || "");
14518
- return;
14566
+ return true;
14519
14567
  }
14568
+ return false;
14520
14569
  },
14521
14570
  [updateToolbarState, isCodeHighlighted, isCodeShiki]
14522
14571
  );
@@ -14560,7 +14609,9 @@ function ToolbarPlugin({
14560
14609
  updateToolbarState("blockType", type);
14561
14610
  } else {
14562
14611
  $handleHeadingNode(element);
14563
- $handleCodeNode(element);
14612
+ if ($handleCodeNode(element)) {
14613
+ return;
14614
+ }
14564
14615
  }
14565
14616
  }
14566
14617
  updateToolbarState(
@@ -14643,7 +14694,7 @@ function ToolbarPlugin({
14643
14694
  ]);
14644
14695
  useEffect43(() => {
14645
14696
  return editor.registerCommand(
14646
- SELECTION_CHANGE_COMMAND4,
14697
+ SELECTION_CHANGE_COMMAND5,
14647
14698
  (_payload, newEditor) => {
14648
14699
  setActiveEditor(newEditor);
14649
14700
  $updateToolbar();
@@ -15912,17 +15963,18 @@ function HtmlPlugin({
15912
15963
  debounceMs = 300
15913
15964
  }) {
15914
15965
  const [editor] = useLexicalComposerContext46();
15915
- const isInternalChange = useRef18(false);
15916
- const lastExternalValue = useRef18(value);
15966
+ const lastSyncedValue = useRef18(null);
15967
+ const hasUserEdited = useRef18(false);
15917
15968
  const debounceTimer = useRef18(null);
15918
15969
  useEffect46(() => {
15919
- if (isInternalChange.current) {
15920
- isInternalChange.current = false;
15970
+ if (value === lastSyncedValue.current) {
15921
15971
  return;
15922
15972
  }
15923
- lastExternalValue.current = value;
15973
+ lastSyncedValue.current = value;
15974
+ hasUserEdited.current = false;
15924
15975
  editor.update(
15925
15976
  () => {
15977
+ $setSelection7(null);
15926
15978
  const root = $getRoot3();
15927
15979
  if (!value || value === "<p></p>" || value === "<p><br></p>") {
15928
15980
  root.clear();
@@ -15939,18 +15991,23 @@ function HtmlPlugin({
15939
15991
  );
15940
15992
  }, [editor, value]);
15941
15993
  const handleChange = useCallback26(
15942
- (_editorState) => {
15994
+ (_editorState, _editor, tags) => {
15995
+ if (!tags.has("historic")) {
15996
+ hasUserEdited.current = true;
15997
+ }
15943
15998
  if (debounceTimer.current) {
15944
15999
  clearTimeout(debounceTimer.current);
15945
16000
  }
15946
16001
  debounceTimer.current = setTimeout(() => {
15947
16002
  editor.update(() => {
15948
16003
  const html = $generateHtmlFromNodes(editor);
15949
- if (html === lastExternalValue.current) {
16004
+ if (html === lastSyncedValue.current) {
16005
+ return;
16006
+ }
16007
+ if (!hasUserEdited.current) {
15950
16008
  return;
15951
16009
  }
15952
- isInternalChange.current = true;
15953
- lastExternalValue.current = html;
16010
+ lastSyncedValue.current = html;
15954
16011
  onChange(html);
15955
16012
  });
15956
16013
  }, debounceMs);