@mdxeditor/editor 4.2.4 → 4.3.0

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.d.ts CHANGED
@@ -112,6 +112,8 @@ export declare function $createImageNode(params: CreateImageNodeParameters): Ima
112
112
  */
113
113
  export declare function $createTableNode(mdastNode: Mdast.Table): TableNode;
114
114
 
115
+ /* Excluded from this release type: $insertDecoratorNodeAtSelection */
116
+
115
117
  /**
116
118
  * Returns true if the given node is a {@link CodeBlockNode}.
117
119
  * @group Code Block
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { MDXEditor } from "./MDXEditor.js";
4
4
  import { defaultSvgIcons } from "./defaultSvgIcons.js";
5
5
  import { MarkdownParseError, UnrecognizedMarkdownConstructError, importMarkdownToLexical, importMdastTreeToLexical } from "./importMarkdownToLexical.js";
6
6
  import { exportLexicalTreeToMdast, exportMarkdownFromLexical } from "./exportMarkdownFromLexical.js";
7
- import { Appender, NESTED_EDITOR_UPDATED_COMMAND, activeEditor$, activeEditorSubscriptions$, activePlugins$, addActivePlugin$, addBottomAreaChild$, addComposerChild$, addEditorWrapper$, addExportVisitor$, addImportVisitor$, addLexicalNode$, addMdastExtension$, addNestedEditorChild$, addSyntaxExtension$, addTableCellEditorChild$, addToMarkdownExtension$, addTopAreaChild$, applyBlockType$, applyFormat$, autoFocus$, bottomAreaChildren$, codeBlockEditorDescriptors$, composerChildren$, contentEditableClassName$, contentEditableRef$, contentEditableWrapperElement$, convertSelectionToNode$, corePlugin, createActiveEditorSubscription$, createRootEditorSubscription$, currentBlockType$, currentFormat$, currentSelection$, defaultCodeBlockLanguage$, directiveDescriptors$, editorInFocus$, editorInTable$, editorRootElementRef$, editorWrapperElementRef$, editorWrappers$, exportVisitors$, historyState$, iconComponentFor$, importVisitors$, inFocus$, initialMarkdown$, initialMarkdownNormalize$, insertDecoratorNode$, insertMarkdown$, jsxComponentDescriptors$, jsxIsAvailable$, jsxKindMismatchPolicy$, lexicalTheme$, markdown$, markdownErrorSignal$, markdownProcessingError$, markdownSourceEditorValue$, mdastExtensions$, muteChange$, nestedEditorChildren$, onBlur$, placeholder$, readOnly$, rootEditor$, rootEditorSubscriptions$, setMarkdown$, spellCheck$, syntaxExtensions$, tableCellEditorChildren$, toMarkdownExtensions$, toMarkdownOptions$, topAreaChildren$, translation$, useTranslation, usedLexicalNodes$, viewMode$ } from "./plugins/core/index.js";
7
+ import { $insertDecoratorNodeAtSelection, Appender, NESTED_EDITOR_UPDATED_COMMAND, activeEditor$, activeEditorSubscriptions$, activePlugins$, addActivePlugin$, addBottomAreaChild$, addComposerChild$, addEditorWrapper$, addExportVisitor$, addImportVisitor$, addLexicalNode$, addMdastExtension$, addNestedEditorChild$, addSyntaxExtension$, addTableCellEditorChild$, addToMarkdownExtension$, addTopAreaChild$, applyBlockType$, applyFormat$, autoFocus$, bottomAreaChildren$, codeBlockEditorDescriptors$, composerChildren$, contentEditableClassName$, contentEditableRef$, contentEditableWrapperElement$, convertSelectionToNode$, corePlugin, createActiveEditorSubscription$, createRootEditorSubscription$, currentBlockType$, currentFormat$, currentSelection$, defaultCodeBlockLanguage$, directiveDescriptors$, editorInFocus$, editorInTable$, editorRootElementRef$, editorWrapperElementRef$, editorWrappers$, exportVisitors$, historyState$, iconComponentFor$, importVisitors$, inFocus$, initialMarkdown$, initialMarkdownNormalize$, insertDecoratorNode$, insertMarkdown$, jsxComponentDescriptors$, jsxIsAvailable$, jsxKindMismatchPolicy$, lexicalTheme$, markdown$, markdownErrorSignal$, markdownProcessingError$, markdownSourceEditorValue$, mdastExtensions$, muteChange$, nestedEditorChildren$, onBlur$, placeholder$, readOnly$, rootEditor$, rootEditorSubscriptions$, setMarkdown$, spellCheck$, syntaxExtensions$, tableCellEditorChildren$, toMarkdownExtensions$, toMarkdownOptions$, topAreaChildren$, translation$, useTranslation, usedLexicalNodes$, viewMode$ } from "./plugins/core/index.js";
8
8
  import { ALL_HEADING_LEVELS, allowedHeadingLevels$, headingsPlugin } from "./plugins/headings/index.js";
9
9
  import { insertThematicBreak$, thematicBreakPlugin } from "./plugins/thematic-break/index.js";
10
10
  import { applyListType$, currentListType$, listsPlugin } from "./plugins/lists/index.js";
@@ -78,6 +78,7 @@ export {
78
78
  $createGenericHTMLNode,
79
79
  $createImageNode,
80
80
  $createTableNode,
81
+ $insertDecoratorNodeAtSelection,
81
82
  $isCodeBlockNode,
82
83
  $isDirectiveNode,
83
84
  $isFrontmatterNode,
@@ -1,10 +1,11 @@
1
1
  import { realmPlugin } from "../../RealmWithPlugins.js";
2
2
  import { createEmptyHistoryState } from "@lexical/history";
3
3
  import { $isHeadingNode } from "@lexical/rich-text";
4
+ import { $isListItemNode } from "@lexical/list";
4
5
  import { $setBlocksType } from "@lexical/selection";
5
- import { $findMatchingParent, $wrapNodeInElement, $insertNodeToNearestRoot } from "@lexical/utils";
6
+ import { $wrapNodeInElement, $findMatchingParent, $insertNodeToNearestRoot } from "@lexical/utils";
6
7
  import { Signal, Cell, withLatestFrom, map, filter, useCellValue, scan } from "@mdxeditor/gurx";
7
- import { createCommand, FORMAT_TEXT_COMMAND, $getSelection, $isRangeSelection, BLUR_COMMAND, COMMAND_PRIORITY_CRITICAL, SELECTION_CHANGE_COMMAND, $getRoot, DecoratorNode, $createParagraphNode, FOCUS_COMMAND, $isRootOrShadowRoot, $insertNodes, $setSelection, ParagraphNode, TextNode } from "lexical";
8
+ import { $insertNodes, $isRootOrShadowRoot, $createParagraphNode, $getSelection, $isRangeSelection, $caretFromPoint, $isTextPointCaret, $splitAtPointCaretNext, createCommand, FORMAT_TEXT_COMMAND, BLUR_COMMAND, COMMAND_PRIORITY_CRITICAL, SELECTION_CHANGE_COMMAND, $getRoot, DecoratorNode, FOCUS_COMMAND, $setSelection, ParagraphNode, TextNode } from "lexical";
8
9
  import { gfmStrikethrough } from "micromark-extension-gfm-strikethrough";
9
10
  import { gfmStrikethroughToMarkdown, gfmStrikethroughFromMarkdown } from "mdast-util-gfm-strikethrough";
10
11
  import { highlightMarkToMarkdown, highlightMarkFromMarkdown } from "mdast-util-highlight-mark";
@@ -438,6 +439,30 @@ const convertSelectionToNode$ = Signal((r) => {
438
439
  });
439
440
  });
440
441
  });
442
+ function $insertDecoratorNodeAtSelection(node) {
443
+ if (node.isInline()) {
444
+ $insertNodes([node]);
445
+ if ($isRootOrShadowRoot(node.getParentOrThrow())) {
446
+ $wrapNodeInElement(node, $createParagraphNode).selectEnd();
447
+ }
448
+ return;
449
+ }
450
+ const selection = $getSelection();
451
+ if ($isRangeSelection(selection)) {
452
+ const listItem = $findMatchingParent(selection.focus.getNode(), $isListItemNode);
453
+ if ($isListItemNode(listItem)) {
454
+ let caret = $caretFromPoint(selection.focus, "next");
455
+ while (caret !== null && ($isTextPointCaret(caret) || !listItem.is(caret.getParentAtCaret()))) {
456
+ caret = $splitAtPointCaretNext(caret);
457
+ }
458
+ if (caret !== null) {
459
+ caret.insert(node);
460
+ return;
461
+ }
462
+ }
463
+ }
464
+ $insertNodeToNearestRoot(node);
465
+ }
441
466
  const insertDecoratorNode$ = Signal((r) => {
442
467
  r.sub(r.pipe(insertDecoratorNode$, withLatestFrom(activeEditor$)), ([nodeFactory, theEditor]) => {
443
468
  theEditor == null ? void 0 : theEditor.focus(
@@ -447,14 +472,7 @@ const insertDecoratorNode$ = Signal((r) => {
447
472
  if ($isRangeSelection(selection)) {
448
473
  theEditor.update(() => {
449
474
  const node = nodeFactory();
450
- if (node.isInline()) {
451
- $insertNodes([node]);
452
- if ($isRootOrShadowRoot(node.getParentOrThrow())) {
453
- $wrapNodeInElement(node, $createParagraphNode).selectEnd();
454
- }
455
- } else {
456
- $insertNodeToNearestRoot(node);
457
- }
475
+ $insertDecoratorNodeAtSelection(node);
458
476
  setTimeout(() => {
459
477
  if ("select" in node && typeof node.select === "function") {
460
478
  node.select();
@@ -611,6 +629,7 @@ function useTranslation() {
611
629
  }
612
630
  export {
613
631
  $createGenericHTMLNode,
632
+ $insertDecoratorNodeAtSelection,
614
633
  $isGenericHTMLNode,
615
634
  Appender,
616
635
  GenericHTMLNode,
@@ -58,7 +58,7 @@ const FrontmatterEditor = ({ yaml, onChange }) => {
58
58
  setFrontmatterDialogOpen(open);
59
59
  }
60
60
  },
61
- /* @__PURE__ */ React__default.createElement(Dialog.Portal, { container: editorRootElementRef == null ? void 0 : editorRootElementRef.current }, /* @__PURE__ */ React__default.createElement(Dialog.Overlay, { className: styles.dialogOverlay }), /* @__PURE__ */ React__default.createElement(Dialog.Content, { className: styles.largeDialogContent, "data-editor-type": "frontmatter" }, /* @__PURE__ */ React__default.createElement(Dialog.Title, { className: styles.dialogTitle }, t("frontmatterEditor.title", "Edit document frontmatter")), /* @__PURE__ */ React__default.createElement(
61
+ /* @__PURE__ */ React__default.createElement(Dialog.Portal, { container: editorRootElementRef == null ? void 0 : editorRootElementRef.current }, /* @__PURE__ */ React__default.createElement(Dialog.Overlay, { className: styles.dialogOverlay }), /* @__PURE__ */ React__default.createElement(Dialog.Content, { className: styles.largeDialogContent, "data-editor-type": "frontmatter" }, /* @__PURE__ */ React__default.createElement(Dialog.Title, { className: styles.dialogTitle }, t("frontmatterEditor.title", "Edit document frontmatter")), /* @__PURE__ */ React__default.createElement(Dialog.Description, { className: styles.visuallyHidden }, t("frontmatterEditor.dialogDescription", "Add, edit, or remove the key-value entries of the document frontmatter.")), /* @__PURE__ */ React__default.createElement(
62
62
  "form",
63
63
  {
64
64
  onSubmit: (e) => {
@@ -46,6 +46,7 @@ const ImageDialog = () => {
46
46
  }
47
47
  },
48
48
  /* @__PURE__ */ React__default.createElement(Dialog.Title, null, t("uploadImage.dialogTitle", "Upload an image")),
49
+ /* @__PURE__ */ React__default.createElement(Dialog.Description, { className: styles.visuallyHidden }, imageUploadHandler !== null ? t("uploadImage.dialogDescription", "Insert an image from a URL or upload one from your device.") : t("uploadImage.dialogDescriptionNoUpload", "Insert an image from a URL.")),
49
50
  /* @__PURE__ */ React__default.createElement(
50
51
  "form",
51
52
  {
@@ -44,7 +44,10 @@ const TableEditor = ({ mdastNode, parentEditor, lexicalTable }) => {
44
44
  }, []);
45
45
  const setActiveCellWithBoundaries = React__default.useCallback(
46
46
  (cell) => {
47
- const colCount = lexicalTable.getColCount();
47
+ const [colCount, rowCount] = parentEditor.getEditorState().read(() => {
48
+ const currentTable = $getTableNodeByKey(tableKey);
49
+ return currentTable ? [currentTable.getColCount(), currentTable.getRowCount()] : [0, 0];
50
+ });
48
51
  if (cell === null) {
49
52
  setActiveCell(null);
50
53
  return;
@@ -58,7 +61,7 @@ const TableEditor = ({ mdastNode, parentEditor, lexicalTable }) => {
58
61
  colIndex = colCount - 1;
59
62
  rowIndex -= 1;
60
63
  }
61
- if (rowIndex > lexicalTable.getRowCount() - 1) {
64
+ if (rowIndex > rowCount - 1) {
62
65
  setActiveCell(null);
63
66
  parentEditor.update(() => {
64
67
  const currentTable = $getTableNodeByKey(tableKey);
@@ -86,7 +89,7 @@ const TableEditor = ({ mdastNode, parentEditor, lexicalTable }) => {
86
89
  }
87
90
  setActiveCell([colIndex, rowIndex]);
88
91
  },
89
- [lexicalTable, parentEditor, tableKey]
92
+ [parentEditor, tableKey]
90
93
  );
91
94
  React__default.useEffect(() => {
92
95
  lexicalTable.focusEmitter.subscribe(setActiveCellWithBoundaries);
@@ -94,28 +97,48 @@ const TableEditor = ({ mdastNode, parentEditor, lexicalTable }) => {
94
97
  const addRowToBottom = React__default.useCallback(
95
98
  (e) => {
96
99
  e.preventDefault();
97
- parentEditor.update(() => {
98
- const currentTable = $getTableNodeByKey(tableKey);
99
- if (!currentTable) {
100
- return;
100
+ let nextCell = null;
101
+ parentEditor.update(
102
+ () => {
103
+ const currentTable = $getTableNodeByKey(tableKey);
104
+ if (!currentTable) {
105
+ return;
106
+ }
107
+ nextCell = [0, currentTable.getRowCount()];
108
+ currentTable.addRowToBottom();
109
+ },
110
+ {
111
+ onUpdate: () => {
112
+ if (nextCell) {
113
+ setActiveCell(nextCell);
114
+ }
115
+ }
101
116
  }
102
- currentTable.addRowToBottom();
103
- setActiveCell([0, currentTable.getRowCount()]);
104
- });
117
+ );
105
118
  },
106
119
  [parentEditor, tableKey]
107
120
  );
108
121
  const addColumnToRight = React__default.useCallback(
109
122
  (e) => {
110
123
  e.preventDefault();
111
- parentEditor.update(() => {
112
- const currentTable = $getTableNodeByKey(tableKey);
113
- if (!currentTable) {
114
- return;
124
+ let nextCell = null;
125
+ parentEditor.update(
126
+ () => {
127
+ const currentTable = $getTableNodeByKey(tableKey);
128
+ if (!currentTable) {
129
+ return;
130
+ }
131
+ nextCell = [currentTable.getColCount(), 0];
132
+ currentTable.addColumnToRight();
133
+ },
134
+ {
135
+ onUpdate: () => {
136
+ if (nextCell) {
137
+ setActiveCell(nextCell);
138
+ }
139
+ }
115
140
  }
116
- currentTable.addColumnToRight();
117
- setActiveCell([currentTable.getColCount(), 0]);
118
- });
141
+ );
119
142
  },
120
143
  [parentEditor, tableKey]
121
144
  );
@@ -384,14 +407,24 @@ const ColumnEditor = ({
384
407
  const [editorRootElementRef, iconComponentFor] = useCellValues(editorRootElementRef$, iconComponentFor$);
385
408
  const insertColumnAt = React__default.useCallback(
386
409
  (colIndex2) => {
387
- parentEditor.update(() => {
388
- const currentTable = $getTableNodeByKey(tableKey);
389
- if (!currentTable) {
390
- return;
410
+ let inserted = false;
411
+ parentEditor.update(
412
+ () => {
413
+ const currentTable = $getTableNodeByKey(tableKey);
414
+ if (!currentTable) {
415
+ return;
416
+ }
417
+ currentTable.insertColumnAt(colIndex2);
418
+ inserted = true;
419
+ },
420
+ {
421
+ onUpdate: () => {
422
+ if (inserted) {
423
+ setActiveCellWithBoundaries([colIndex2, 0]);
424
+ }
425
+ }
391
426
  }
392
- currentTable.insertColumnAt(colIndex2);
393
- setActiveCellWithBoundaries([colIndex2, 0]);
394
- });
427
+ );
395
428
  },
396
429
  [parentEditor, setActiveCellWithBoundaries, tableKey]
397
430
  );
@@ -475,14 +508,24 @@ const RowEditor = ({
475
508
  const [editorRootElementRef, iconComponentFor] = useCellValues(editorRootElementRef$, iconComponentFor$);
476
509
  const insertRowAt = React__default.useCallback(
477
510
  (rowIndex2) => {
478
- parentEditor.update(() => {
479
- const currentTable = $getTableNodeByKey(tableKey);
480
- if (!currentTable) {
481
- return;
511
+ let inserted = false;
512
+ parentEditor.update(
513
+ () => {
514
+ const currentTable = $getTableNodeByKey(tableKey);
515
+ if (!currentTable) {
516
+ return;
517
+ }
518
+ currentTable.insertRowAt(rowIndex2);
519
+ inserted = true;
520
+ },
521
+ {
522
+ onUpdate: () => {
523
+ if (inserted) {
524
+ setActiveCellWithBoundaries([0, rowIndex2]);
525
+ }
526
+ }
482
527
  }
483
- currentTable.insertRowAt(rowIndex2);
484
- setActiveCellWithBoundaries([0, rowIndex2]);
485
- });
528
+ );
486
529
  },
487
530
  [parentEditor, setActiveCellWithBoundaries, tableKey]
488
531
  );
@@ -18,7 +18,7 @@ const DialogButton = React__default.forwardRef(({ autocompleteSuggestions = [],
18
18
  },
19
19
  [onSubmit]
20
20
  );
21
- return /* @__PURE__ */ React__default.createElement(Dialog.Root, { open, onOpenChange: setOpen }, /* @__PURE__ */ React__default.createElement(Dialog.Trigger, { asChild: true }, /* @__PURE__ */ React__default.createElement(RadixToolbar.Button, { "aria-label": tooltipTitle, className: styles.toolbarButton, ref: forwardedRef, disabled: readOnly }, /* @__PURE__ */ React__default.createElement(TooltipWrap, { title: tooltipTitle }, buttonContent))), /* @__PURE__ */ React__default.createElement(Dialog.Portal, { container: editorRootElementRef == null ? void 0 : editorRootElementRef.current }, /* @__PURE__ */ React__default.createElement(Dialog.Overlay, { className: styles.dialogOverlay }), /* @__PURE__ */ React__default.createElement(Dialog.Content, { className: styles.dialogContent }, /* @__PURE__ */ React__default.createElement(
21
+ return /* @__PURE__ */ React__default.createElement(Dialog.Root, { open, onOpenChange: setOpen }, /* @__PURE__ */ React__default.createElement(Dialog.Trigger, { asChild: true }, /* @__PURE__ */ React__default.createElement(RadixToolbar.Button, { "aria-label": tooltipTitle, className: styles.toolbarButton, ref: forwardedRef, disabled: readOnly }, /* @__PURE__ */ React__default.createElement(TooltipWrap, { title: tooltipTitle }, buttonContent))), /* @__PURE__ */ React__default.createElement(Dialog.Portal, { container: editorRootElementRef == null ? void 0 : editorRootElementRef.current }, /* @__PURE__ */ React__default.createElement(Dialog.Overlay, { className: styles.dialogOverlay }), /* @__PURE__ */ React__default.createElement(Dialog.Content, { className: styles.dialogContent }, /* @__PURE__ */ React__default.createElement(Dialog.Title, { className: styles.visuallyHidden }, tooltipTitle), /* @__PURE__ */ React__default.createElement(Dialog.Description, { className: styles.visuallyHidden }, dialogInputPlaceholder), /* @__PURE__ */ React__default.createElement(
22
22
  DialogForm,
23
23
  {
24
24
  submitButtonTitle,