@nkzw/mdx-editor 0.1.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.
Files changed (148) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +86 -0
  3. package/UPSTREAM.md +21 -0
  4. package/dist/EditorIcon.js +75 -0
  5. package/dist/FormatConstants.js +20 -0
  6. package/dist/MDXEditor.js +189 -0
  7. package/dist/MarkdownEditor.js +281 -0
  8. package/dist/PersistentMarkdownEditor.js +358 -0
  9. package/dist/RealmWithPlugins.js +35 -0
  10. package/dist/core.d.ts +3232 -0
  11. package/dist/core.js +354 -0
  12. package/dist/defaultSvgIcons.js +371 -0
  13. package/dist/directive-editors/AdmonitionDirectiveDescriptor.js +28 -0
  14. package/dist/directive-editors/GenericDirectiveEditor.js +37 -0
  15. package/dist/exportMarkdownFromLexical.js +262 -0
  16. package/dist/horizontalRuleShortcut.js +37 -0
  17. package/dist/importMarkdownToLexical.js +172 -0
  18. package/dist/index.d.ts +86 -0
  19. package/dist/index.js +8 -0
  20. package/dist/jsx-editors/GenericJsxEditor.js +84 -0
  21. package/dist/mdastUtilHtmlComment.js +125 -0
  22. package/dist/persistence.d.ts +128 -0
  23. package/dist/persistence.js +4 -0
  24. package/dist/plugins/codeblock/CodeBlockNode.js +183 -0
  25. package/dist/plugins/codeblock/CodeBlockVisitor.js +14 -0
  26. package/dist/plugins/codeblock/MdastCodeVisitor.js +23 -0
  27. package/dist/plugins/codeblock/findCodeBlockDescriptor.js +8 -0
  28. package/dist/plugins/codeblock/index.js +46 -0
  29. package/dist/plugins/codemirror/CodeMirrorEditor.js +145 -0
  30. package/dist/plugins/codemirror/index.js +115 -0
  31. package/dist/plugins/codemirror/useCodeMirrorRef.js +101 -0
  32. package/dist/plugins/core/GenericHTMLNode.js +118 -0
  33. package/dist/plugins/core/LexicalGenericHTMLNodeVisitor.js +15 -0
  34. package/dist/plugins/core/LexicalLinebreakVisitor.js +10 -0
  35. package/dist/plugins/core/LexicalParagraphVisitor.js +10 -0
  36. package/dist/plugins/core/LexicalRootVisitor.js +10 -0
  37. package/dist/plugins/core/LexicalTextVisitor.js +160 -0
  38. package/dist/plugins/core/MdastBreakVisitor.js +10 -0
  39. package/dist/plugins/core/MdastFormattingVisitor.js +81 -0
  40. package/dist/plugins/core/MdastHTMLNode.js +120 -0
  41. package/dist/plugins/core/MdastHTMLVisitor.js +17 -0
  42. package/dist/plugins/core/MdastParagraphVisitor.js +23 -0
  43. package/dist/plugins/core/MdastRootVisitor.js +9 -0
  44. package/dist/plugins/core/MdastTextVisitor.js +16 -0
  45. package/dist/plugins/core/NestedLexicalEditor.js +221 -0
  46. package/dist/plugins/core/PropertyPopover.js +75 -0
  47. package/dist/plugins/core/SharedHistoryPlugin.js +10 -0
  48. package/dist/plugins/core/index.js +692 -0
  49. package/dist/plugins/core/ui/DownshiftAutoComplete.js +89 -0
  50. package/dist/plugins/core/ui/PopoverUtils.js +22 -0
  51. package/dist/plugins/diff-source/DiffSourceWrapper.js +24 -0
  52. package/dist/plugins/diff-source/DiffViewer.js +84 -0
  53. package/dist/plugins/diff-source/SourceEditor.js +60 -0
  54. package/dist/plugins/diff-source/index.js +27 -0
  55. package/dist/plugins/directives/DirectiveNode.js +107 -0
  56. package/dist/plugins/directives/DirectiveVisitor.js +10 -0
  57. package/dist/plugins/directives/MdastDirectiveVisitor.js +30 -0
  58. package/dist/plugins/directives/index.js +45 -0
  59. package/dist/plugins/frontmatter/FrontmatterEditor.js +137 -0
  60. package/dist/plugins/frontmatter/FrontmatterNode.js +70 -0
  61. package/dist/plugins/frontmatter/LexicalFrontmatterVisitor.js +10 -0
  62. package/dist/plugins/frontmatter/MdastFrontmatterVisitor.js +10 -0
  63. package/dist/plugins/frontmatter/index.js +113 -0
  64. package/dist/plugins/headings/LexicalHeadingVisitor.js +11 -0
  65. package/dist/plugins/headings/MdastHeadingVisitor.js +10 -0
  66. package/dist/plugins/headings/index.js +63 -0
  67. package/dist/plugins/image/EditImageToolbar.js +58 -0
  68. package/dist/plugins/image/ImageDialog.js +132 -0
  69. package/dist/plugins/image/ImageEditor.js +279 -0
  70. package/dist/plugins/image/ImageNode.js +187 -0
  71. package/dist/plugins/image/ImagePlaceholder.js +9 -0
  72. package/dist/plugins/image/ImageResizer.js +223 -0
  73. package/dist/plugins/image/LexicalImageVisitor.js +42 -0
  74. package/dist/plugins/image/MdastImageVisitor.js +91 -0
  75. package/dist/plugins/image/index.js +364 -0
  76. package/dist/plugins/jsx/LexicalJsxNode.js +103 -0
  77. package/dist/plugins/jsx/LexicalJsxVisitor.js +27 -0
  78. package/dist/plugins/jsx/LexicalMdxExpressionNode.js +130 -0
  79. package/dist/plugins/jsx/LexicalMdxExpressionVisitor.js +14 -0
  80. package/dist/plugins/jsx/MdastMdxExpressionVisitor.js +11 -0
  81. package/dist/plugins/jsx/MdastMdxJsEsmVisitor.js +8 -0
  82. package/dist/plugins/jsx/MdastMdxJsxElementVisitor.js +28 -0
  83. package/dist/plugins/jsx/index.js +97 -0
  84. package/dist/plugins/jsx/jsxTagName.js +7 -0
  85. package/dist/plugins/link/AutoLinkPlugin.js +18 -0
  86. package/dist/plugins/link/LexicalLinkVisitor.js +10 -0
  87. package/dist/plugins/link/MdastLinkVisitor.js +14 -0
  88. package/dist/plugins/link/index.js +34 -0
  89. package/dist/plugins/link-dialog/LinkDialog.js +262 -0
  90. package/dist/plugins/link-dialog/index.js +304 -0
  91. package/dist/plugins/lists/CheckListPlugin.js +270 -0
  92. package/dist/plugins/lists/LexicalListItemVisitor.js +41 -0
  93. package/dist/plugins/lists/LexicalListVisitor.js +13 -0
  94. package/dist/plugins/lists/MdastListItemVisitor.js +11 -0
  95. package/dist/plugins/lists/MdastListVisitor.js +19 -0
  96. package/dist/plugins/lists/NotesListItemNode.js +22 -0
  97. package/dist/plugins/lists/index.js +111 -0
  98. package/dist/plugins/markdown-shortcut/index.js +114 -0
  99. package/dist/plugins/maxlength/index.js +36 -0
  100. package/dist/plugins/quote/LexicalQuoteVisitor.js +10 -0
  101. package/dist/plugins/quote/MdastBlockQuoteVisitor.js +10 -0
  102. package/dist/plugins/quote/index.js +18 -0
  103. package/dist/plugins/remote/index.js +52 -0
  104. package/dist/plugins/search/index.js +360 -0
  105. package/dist/plugins/table/LexicalTableVisitor.js +10 -0
  106. package/dist/plugins/table/MdastTableVisitor.js +10 -0
  107. package/dist/plugins/table/TableEditor.js +527 -0
  108. package/dist/plugins/table/TableNode.js +208 -0
  109. package/dist/plugins/table/index.js +66 -0
  110. package/dist/plugins/thematic-break/LexicalThematicBreakVisitor.js +10 -0
  111. package/dist/plugins/thematic-break/MdastThematicBreakVisitor.js +10 -0
  112. package/dist/plugins/thematic-break/index.js +27 -0
  113. package/dist/plugins/toolbar/components/BlockTypeSelect.js +62 -0
  114. package/dist/plugins/toolbar/components/BoldItalicUnderlineToggles.js +98 -0
  115. package/dist/plugins/toolbar/components/ChangeAdmonitionType.js +43 -0
  116. package/dist/plugins/toolbar/components/ChangeCodeMirrorLanguage.js +42 -0
  117. package/dist/plugins/toolbar/components/CodeToggle.js +21 -0
  118. package/dist/plugins/toolbar/components/CreateLink.js +24 -0
  119. package/dist/plugins/toolbar/components/DiffSourceToggleWrapper.js +42 -0
  120. package/dist/plugins/toolbar/components/HighlightToggle.js +28 -0
  121. package/dist/plugins/toolbar/components/InsertAdmonition.js +34 -0
  122. package/dist/plugins/toolbar/components/InsertCodeBlock.js +23 -0
  123. package/dist/plugins/toolbar/components/InsertFrontmatter.js +28 -0
  124. package/dist/plugins/toolbar/components/InsertImage.js +29 -0
  125. package/dist/plugins/toolbar/components/InsertTable.js +25 -0
  126. package/dist/plugins/toolbar/components/InsertThematicBreak.js +23 -0
  127. package/dist/plugins/toolbar/components/KitchenSinkToolbar.js +82 -0
  128. package/dist/plugins/toolbar/components/ListsToggle.js +29 -0
  129. package/dist/plugins/toolbar/components/UndoRedo.js +60 -0
  130. package/dist/plugins/toolbar/index.js +32 -0
  131. package/dist/plugins/toolbar/primitives/DialogButton.js +130 -0
  132. package/dist/plugins/toolbar/primitives/TooltipWrap.js +17 -0
  133. package/dist/plugins/toolbar/primitives/select.js +76 -0
  134. package/dist/plugins/toolbar/primitives/toolbar.js +144 -0
  135. package/dist/registerCodeBoundaryEscape.js +40 -0
  136. package/dist/styles/lexical-theme.module.css.js +62 -0
  137. package/dist/styles/lexicalTheme.js +32 -0
  138. package/dist/styles/ui.module.css.js +296 -0
  139. package/dist/styles.css +2838 -0
  140. package/dist/utils/detectMac.js +16 -0
  141. package/dist/utils/fp.js +44 -0
  142. package/dist/utils/isPartOftheEditorUI.js +12 -0
  143. package/dist/utils/lexicalHelpers.js +185 -0
  144. package/dist/utils/makeHslTransparent.js +6 -0
  145. package/dist/utils/mergeStyleAttributes.js +22 -0
  146. package/dist/utils/uuid4.js +10 -0
  147. package/dist/utils/voidEmitter.js +15 -0
  148. package/package.json +133 -0
@@ -0,0 +1,42 @@
1
+ import { $isImageNode } from "./ImageNode.js";
2
+ const LexicalImageVisitor = {
3
+ testLexicalNode: $isImageNode,
4
+ visitLexicalNode({ mdastParent, lexicalNode, actions }) {
5
+ if (lexicalNode.shouldBeSerializedAsElement()) {
6
+ const img = new Image();
7
+ if (lexicalNode.getHeight() !== "inherit") {
8
+ img.height = lexicalNode.getHeight();
9
+ }
10
+ if (lexicalNode.getWidth() !== "inherit") {
11
+ img.width = lexicalNode.getWidth();
12
+ }
13
+ if (lexicalNode.getAltText()) {
14
+ img.alt = lexicalNode.getAltText();
15
+ }
16
+ if (lexicalNode.getTitle()) {
17
+ img.title = lexicalNode.getTitle();
18
+ }
19
+ for (const attr of lexicalNode.getRest()) {
20
+ if (attr.type === "mdxJsxAttribute") {
21
+ if (typeof attr.value === "string") {
22
+ img.setAttribute(attr.name, attr.value);
23
+ }
24
+ }
25
+ }
26
+ actions.appendToParent(mdastParent, {
27
+ type: "html",
28
+ value: img.outerHTML.replace(/>$/, ` src="${lexicalNode.getSrc()}" />`)
29
+ });
30
+ } else {
31
+ actions.appendToParent(mdastParent, {
32
+ type: "image",
33
+ url: lexicalNode.getSrc(),
34
+ alt: lexicalNode.getAltText(),
35
+ title: lexicalNode.getTitle()
36
+ });
37
+ }
38
+ }
39
+ };
40
+ export {
41
+ LexicalImageVisitor
42
+ };
@@ -0,0 +1,91 @@
1
+ import { $createImageNode } from "./ImageNode.js";
2
+ import { $createParagraphNode } from "lexical";
3
+ const MdastImageVisitor = {
4
+ testNode: "image",
5
+ visitNode({ mdastNode, actions }) {
6
+ actions.addAndStepInto(
7
+ $createImageNode({
8
+ src: mdastNode.url,
9
+ altText: mdastNode.alt ?? "",
10
+ title: mdastNode.title ?? ""
11
+ })
12
+ );
13
+ }
14
+ };
15
+ const MdastHtmlImageVisitor = {
16
+ testNode: (node) => {
17
+ return node.type === "html" && node.value.trim().startsWith("<img");
18
+ },
19
+ visitNode({ mdastNode, lexicalParent }) {
20
+ const wrapper = document.createElement("div");
21
+ wrapper.innerHTML = mdastNode.value;
22
+ const img = wrapper.querySelector("img");
23
+ if (!img) {
24
+ throw new Error("Invalid HTML image");
25
+ }
26
+ const src = img.src;
27
+ const altText = img.alt;
28
+ const title = img.title;
29
+ const width = img.width;
30
+ const height = img.height;
31
+ const image = $createImageNode({
32
+ src: src || "",
33
+ altText,
34
+ title,
35
+ width: width || void 0,
36
+ height: height || void 0
37
+ });
38
+ if (lexicalParent.getType() === "root") {
39
+ const paragraph = $createParagraphNode();
40
+ paragraph.append(image);
41
+ lexicalParent.append(paragraph);
42
+ } else {
43
+ lexicalParent.append(image);
44
+ }
45
+ }
46
+ };
47
+ function getAttributeValue(node, attributeName) {
48
+ const attribute = node.attributes.find((a) => a.type === "mdxJsxAttribute" && a.name === attributeName);
49
+ if (!attribute) {
50
+ return void 0;
51
+ }
52
+ return attribute.value;
53
+ }
54
+ const MdastJsxImageVisitor = {
55
+ testNode: (node) => {
56
+ return (node.type === "mdxJsxTextElement" || node.type === "mdxJsxFlowElement") && node.name === "img";
57
+ },
58
+ visitNode({ mdastNode, lexicalParent }) {
59
+ const src = getAttributeValue(mdastNode, "src");
60
+ if (!src) {
61
+ return;
62
+ }
63
+ const altText = getAttributeValue(mdastNode, "alt") ?? "";
64
+ const title = getAttributeValue(mdastNode, "title");
65
+ const height = getAttributeValue(mdastNode, "height");
66
+ const width = getAttributeValue(mdastNode, "width");
67
+ const rest = mdastNode.attributes.filter((a) => {
68
+ return a.type === "mdxJsxAttribute" && !["src", "alt", "title", "height", "width"].includes(a.name);
69
+ });
70
+ const image = $createImageNode({
71
+ src,
72
+ altText,
73
+ title,
74
+ width: width ? parseInt(width, 10) : void 0,
75
+ height: height ? parseInt(height, 10) : void 0,
76
+ rest
77
+ });
78
+ if (lexicalParent.getType() === "root") {
79
+ const paragraph = $createParagraphNode();
80
+ paragraph.append(image);
81
+ lexicalParent.append(paragraph);
82
+ } else {
83
+ lexicalParent.append(image);
84
+ }
85
+ }
86
+ };
87
+ export {
88
+ MdastHtmlImageVisitor,
89
+ MdastImageVisitor,
90
+ MdastJsxImageVisitor
91
+ };
@@ -0,0 +1,364 @@
1
+ import { ImagePlaceholder } from "./ImagePlaceholder.js";
2
+ import { mergeRegister, $wrapNodeInElement } from "@lexical/utils";
3
+ import { Cell, Action, mapTo, withLatestFrom, Signal, map } from "@mdxeditor/gurx";
4
+ import { createCommand, $getNodeByKey, $insertNodes, $isRootOrShadowRoot, $createParagraphNode, COMMAND_PRIORITY_EDITOR, DRAGSTART_COMMAND, COMMAND_PRIORITY_HIGH, DRAGOVER_COMMAND, COMMAND_PRIORITY_LOW, DROP_COMMAND, PASTE_COMMAND, COMMAND_PRIORITY_CRITICAL, $createRangeSelection, $setSelection, $getSelection, $isNodeSelection } from "lexical";
5
+ import { realmPlugin } from "../../RealmWithPlugins.js";
6
+ import { CAN_USE_DOM } from "../../utils/detectMac.js";
7
+ import { activeEditor$, createActiveEditorSubscription$, addComposerChild$, addExportVisitor$, addLexicalNode$, addImportVisitor$ } from "../core/index.js";
8
+ import { EditImageToolbar } from "./EditImageToolbar.js";
9
+ import { ImageDialog } from "./ImageDialog.js";
10
+ import { $createImageNode, $isImageNode, ImageNode } from "./ImageNode.js";
11
+ import { LexicalImageVisitor } from "./LexicalImageVisitor.js";
12
+ import { MdastImageVisitor, MdastHtmlImageVisitor, MdastJsxImageVisitor } from "./MdastImageVisitor.js";
13
+ const internalInsertImage$ = Signal((r) => {
14
+ r.sub(r.pipe(internalInsertImage$, withLatestFrom(activeEditor$)), ([values, theEditor]) => {
15
+ theEditor?.update(() => {
16
+ const imageNode = $createImageNode({
17
+ altText: values.altText ?? "",
18
+ src: values.src,
19
+ title: values.title ?? "",
20
+ width: parseImageDimension(values.width),
21
+ height: parseImageDimension(values.height)
22
+ });
23
+ $insertNodes([imageNode]);
24
+ if ($isRootOrShadowRoot(imageNode.getParentOrThrow())) {
25
+ $wrapNodeInElement(imageNode, $createParagraphNode).selectEnd();
26
+ }
27
+ });
28
+ });
29
+ });
30
+ const insertImage$ = Signal((r) => {
31
+ r.sub(r.pipe(insertImage$, withLatestFrom(imageUploadHandler$)), ([values, imageUploadHandler]) => {
32
+ const handler = (src) => {
33
+ r.pub(internalInsertImage$, { ...values, src });
34
+ };
35
+ if ("file" in values) {
36
+ imageUploadHandler?.(values.file).then(handler).catch((e) => {
37
+ throw e;
38
+ });
39
+ } else {
40
+ handler(values.src);
41
+ }
42
+ });
43
+ });
44
+ const imageAutocompleteSuggestions$ = Cell([]);
45
+ const disableImageResize$ = Cell(false);
46
+ const imageUploadHandler$ = Cell(null);
47
+ const imagePreviewHandler$ = Cell(null);
48
+ const imagePlaceholder$ = Cell(null);
49
+ const imageDialogState$ = Cell(
50
+ { type: "inactive" },
51
+ (r) => {
52
+ r.sub(
53
+ r.pipe(saveImage$, withLatestFrom(activeEditor$, imageUploadHandler$, imageDialogState$, allowSetImageDimensions$)),
54
+ ([values, theEditor, imageUploadHandler, dialogState, allowSetImageDimensions]) => {
55
+ const handler = dialogState.type === "editing" ? (src) => {
56
+ theEditor?.update(() => {
57
+ const { nodeKey } = dialogState;
58
+ const imageNode = $getNodeByKey(nodeKey);
59
+ imageNode.setTitle(values.title);
60
+ imageNode.setAltText(values.altText);
61
+ imageNode.setSrc(src);
62
+ if (allowSetImageDimensions) {
63
+ const width = parseImageDimension(values.width);
64
+ const height = parseImageDimension(values.height);
65
+ imageNode.setWidthAndHeight(width ?? "inherit", height ?? "inherit");
66
+ }
67
+ });
68
+ r.pub(imageDialogState$, { type: "inactive" });
69
+ } : (src) => {
70
+ r.pub(internalInsertImage$, { ...values, src });
71
+ r.pub(imageDialogState$, { type: "inactive" });
72
+ };
73
+ if (values.file && values.file.length > 0) {
74
+ imageUploadHandler?.(values.file.item(0)).then(handler).catch((e) => {
75
+ throw e;
76
+ });
77
+ } else if (values.src) {
78
+ handler(values.src);
79
+ }
80
+ }
81
+ );
82
+ r.pub(createActiveEditorSubscription$, (editor) => {
83
+ const theUploadHandler = r.getValue(imageUploadHandler$);
84
+ return mergeRegister(
85
+ editor.registerCommand(
86
+ INSERT_IMAGE_COMMAND,
87
+ (payload) => {
88
+ const imageNode = $createImageNode(payload);
89
+ $insertNodes([imageNode]);
90
+ if ($isRootOrShadowRoot(imageNode.getParentOrThrow())) {
91
+ $wrapNodeInElement(imageNode, $createParagraphNode).selectEnd();
92
+ }
93
+ return true;
94
+ },
95
+ COMMAND_PRIORITY_EDITOR
96
+ ),
97
+ editor.registerCommand(
98
+ DRAGSTART_COMMAND,
99
+ (event) => {
100
+ return onDragStart(event);
101
+ },
102
+ COMMAND_PRIORITY_HIGH
103
+ ),
104
+ editor.registerCommand(
105
+ DRAGOVER_COMMAND,
106
+ (event) => {
107
+ return onDragover(event, !!theUploadHandler);
108
+ },
109
+ COMMAND_PRIORITY_LOW
110
+ ),
111
+ editor.registerCommand(
112
+ DROP_COMMAND,
113
+ (event) => {
114
+ return onDrop(event, editor, r.getValue(imageUploadHandler$));
115
+ },
116
+ COMMAND_PRIORITY_HIGH
117
+ ),
118
+ editor.registerCommand(
119
+ PASTE_COMMAND,
120
+ (event) => {
121
+ if (!theUploadHandler) {
122
+ let fromWeb = Array.from(event.clipboardData?.items ?? []);
123
+ fromWeb = fromWeb.filter((i) => i.type.includes("text"));
124
+ if (!fromWeb.length || fromWeb.length === 0) {
125
+ return true;
126
+ }
127
+ return false;
128
+ }
129
+ const cbPayload = Array.from(event.clipboardData?.items ?? []);
130
+ const isMixedPayload = cbPayload.some((item) => !item.type.includes("image"));
131
+ if (isMixedPayload) return false;
132
+ if (!cbPayload.length || cbPayload.length === 0) {
133
+ return false;
134
+ }
135
+ const imageUploadHandlerValue = r.getValue(imageUploadHandler$);
136
+ Promise.all(cbPayload.map((file) => imageUploadHandlerValue(file.getAsFile()))).then((urls) => {
137
+ urls.forEach((url) => {
138
+ editor.dispatchCommand(INSERT_IMAGE_COMMAND, {
139
+ src: url,
140
+ altText: ""
141
+ });
142
+ });
143
+ }).catch((e) => {
144
+ throw e;
145
+ });
146
+ return true;
147
+ },
148
+ COMMAND_PRIORITY_CRITICAL
149
+ )
150
+ );
151
+ });
152
+ }
153
+ );
154
+ const openNewImageDialog$ = Action((r) => {
155
+ r.link(r.pipe(openNewImageDialog$, mapTo({ type: "new" })), imageDialogState$);
156
+ });
157
+ const openEditImageDialog$ = Signal((r) => {
158
+ r.link(
159
+ r.pipe(
160
+ openEditImageDialog$,
161
+ map((payload) => ({ type: "editing", ...payload }))
162
+ ),
163
+ imageDialogState$
164
+ );
165
+ });
166
+ const closeImageDialog$ = Action((r) => {
167
+ r.link(r.pipe(closeImageDialog$, mapTo({ type: "inactive" })), imageDialogState$);
168
+ });
169
+ const disableImageSettingsButton$ = Cell(false);
170
+ const allowSetImageDimensions$ = Cell(false);
171
+ const saveImage$ = Signal();
172
+ const editImageToolbarComponent$ = Cell(EditImageToolbar);
173
+ const parseImageDimension = (value) => {
174
+ if (typeof value === "undefined") return void 0;
175
+ const parsed = parseInt(String(value), 10);
176
+ return Number.isNaN(parsed) ? void 0 : parsed;
177
+ };
178
+ const imagePlugin = realmPlugin({
179
+ init(realm, params) {
180
+ realm.pubIn({
181
+ [addImportVisitor$]: [MdastImageVisitor, MdastHtmlImageVisitor, MdastJsxImageVisitor],
182
+ [addLexicalNode$]: ImageNode,
183
+ [addExportVisitor$]: LexicalImageVisitor,
184
+ [addComposerChild$]: params?.ImageDialog ?? ImageDialog,
185
+ [imageUploadHandler$]: params?.imageUploadHandler ?? null,
186
+ [imageAutocompleteSuggestions$]: params?.imageAutocompleteSuggestions ?? [],
187
+ [disableImageResize$]: Boolean(params?.disableImageResize),
188
+ [disableImageSettingsButton$]: Boolean(params?.disableImageSettingsButton),
189
+ [allowSetImageDimensions$]: Boolean(params?.allowSetImageDimensions),
190
+ [imagePreviewHandler$]: params?.imagePreviewHandler ?? null,
191
+ [editImageToolbarComponent$]: params?.EditImageToolbar ?? EditImageToolbar,
192
+ [imagePlaceholder$]: params?.imagePlaceholder ?? ImagePlaceholder
193
+ });
194
+ },
195
+ update(realm, params) {
196
+ realm.pubIn({
197
+ [imageUploadHandler$]: params?.imageUploadHandler ?? null,
198
+ [imageAutocompleteSuggestions$]: params?.imageAutocompleteSuggestions ?? [],
199
+ [disableImageResize$]: Boolean(params?.disableImageResize),
200
+ [imagePreviewHandler$]: params?.imagePreviewHandler ?? null,
201
+ [allowSetImageDimensions$]: Boolean(params?.allowSetImageDimensions),
202
+ [editImageToolbarComponent$]: params?.EditImageToolbar ?? EditImageToolbar,
203
+ [imagePlaceholder$]: params?.imagePlaceholder ?? ImagePlaceholder
204
+ });
205
+ }
206
+ });
207
+ const getDOMSelection = (targetWindow) => CAN_USE_DOM ? (targetWindow ?? window).getSelection() : null;
208
+ const INSERT_IMAGE_COMMAND = createCommand("INSERT_IMAGE_COMMAND");
209
+ const TRANSPARENT_IMAGE = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
210
+ function onDragStart(event) {
211
+ const node = getImageNodeInSelection();
212
+ if (!node) {
213
+ return false;
214
+ }
215
+ const dataTransfer = event.dataTransfer;
216
+ if (!dataTransfer) {
217
+ return false;
218
+ }
219
+ dataTransfer.setData("text/plain", "_");
220
+ const img = document.createElement("img");
221
+ img.src = TRANSPARENT_IMAGE;
222
+ dataTransfer.setDragImage(img, 0, 0);
223
+ dataTransfer.setData(
224
+ "application/x-lexical-drag",
225
+ JSON.stringify({
226
+ data: {
227
+ altText: node.__altText,
228
+ title: node.__title,
229
+ key: node.getKey(),
230
+ src: node.__src
231
+ },
232
+ type: "image"
233
+ })
234
+ );
235
+ return true;
236
+ }
237
+ function onDragover(event, hasUploadHandler) {
238
+ if (hasUploadHandler) {
239
+ let cbPayload = Array.from(event.dataTransfer?.items ?? []);
240
+ cbPayload = cbPayload.filter((i) => i.type.includes("image"));
241
+ if (cbPayload.length > 0) {
242
+ event.preventDefault();
243
+ return true;
244
+ }
245
+ }
246
+ const node = getImageNodeInSelection();
247
+ if (!node) {
248
+ return false;
249
+ }
250
+ if (!canDropImage(event)) {
251
+ event.preventDefault();
252
+ }
253
+ return true;
254
+ }
255
+ function onDrop(event, editor, imageUploadHandler) {
256
+ let cbPayload = Array.from(event.dataTransfer?.items ?? []);
257
+ cbPayload = cbPayload.filter((i) => i.type.includes("image"));
258
+ if (cbPayload.length > 0) {
259
+ if (imageUploadHandler !== null) {
260
+ event.preventDefault();
261
+ Promise.all(
262
+ cbPayload.map((image) => {
263
+ if (image.kind === "string") {
264
+ return new Promise((rs) => {
265
+ image.getAsString(rs);
266
+ });
267
+ }
268
+ return imageUploadHandler(image.getAsFile());
269
+ })
270
+ ).then((urls) => {
271
+ urls.forEach((url) => {
272
+ editor.dispatchCommand(INSERT_IMAGE_COMMAND, {
273
+ src: url,
274
+ altText: ""
275
+ });
276
+ });
277
+ }).catch((e) => {
278
+ throw e;
279
+ });
280
+ return true;
281
+ }
282
+ }
283
+ const node = getImageNodeInSelection();
284
+ if (!node) {
285
+ return false;
286
+ }
287
+ const data = getDragImageData(event);
288
+ if (!data) {
289
+ return false;
290
+ }
291
+ event.preventDefault();
292
+ if (canDropImage(event)) {
293
+ const range = getDragSelection(event);
294
+ node.remove();
295
+ const rangeSelection = $createRangeSelection();
296
+ if (range !== null && range !== void 0) {
297
+ rangeSelection.applyDOMRange(range);
298
+ }
299
+ $setSelection(rangeSelection);
300
+ editor.dispatchCommand(INSERT_IMAGE_COMMAND, data);
301
+ }
302
+ return true;
303
+ }
304
+ function getImageNodeInSelection() {
305
+ const selection = $getSelection();
306
+ if (!$isNodeSelection(selection)) {
307
+ return null;
308
+ }
309
+ const nodes = selection.getNodes();
310
+ const node = nodes[0];
311
+ return $isImageNode(node) ? node : null;
312
+ }
313
+ function getDragImageData(event) {
314
+ const dragData = event.dataTransfer?.getData("application/x-lexical-drag");
315
+ if (!dragData) {
316
+ return null;
317
+ }
318
+ const { type, data } = JSON.parse(dragData);
319
+ if (type !== "image") {
320
+ return null;
321
+ }
322
+ return data;
323
+ }
324
+ function canDropImage(event) {
325
+ const target = event.target;
326
+ return !!(target && target instanceof HTMLElement && target.parentElement);
327
+ }
328
+ function getDragSelection(event) {
329
+ let range;
330
+ const target = event.target;
331
+ const targetWindow = target == null ? null : target.nodeType === 9 ? target.defaultView : target.ownerDocument.defaultView;
332
+ const domSelection = getDOMSelection(targetWindow);
333
+ if (document.caretRangeFromPoint) {
334
+ range = document.caretRangeFromPoint(event.clientX, event.clientY);
335
+ } else if (event.rangeParent && domSelection !== null) {
336
+ domSelection.collapse(event.rangeParent, event.rangeOffset ?? 0);
337
+ range = domSelection.getRangeAt(0);
338
+ } else {
339
+ throw Error(`Cannot get the selection when dragging`);
340
+ }
341
+ return range;
342
+ }
343
+ export {
344
+ $createImageNode,
345
+ $isImageNode,
346
+ INSERT_IMAGE_COMMAND,
347
+ ImageNode,
348
+ allowSetImageDimensions$,
349
+ closeImageDialog$,
350
+ disableImageResize$,
351
+ disableImageSettingsButton$,
352
+ editImageToolbarComponent$,
353
+ imageAutocompleteSuggestions$,
354
+ imageDialogState$,
355
+ imagePlaceholder$,
356
+ imagePlugin,
357
+ imagePreviewHandler$,
358
+ imageUploadHandler$,
359
+ insertImage$,
360
+ openEditImageDialog$,
361
+ openNewImageDialog$,
362
+ parseImageDimension,
363
+ saveImage$
364
+ };
@@ -0,0 +1,103 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { DecoratorNode } from "lexical";
3
+ import { NestedEditorsContext } from "../core/NestedLexicalEditor.js";
4
+ import { voidEmitter } from "../../utils/voidEmitter.js";
5
+ import { useCellValue } from "@mdxeditor/gurx";
6
+ import { jsxComponentDescriptors$ } from "../core/index.js";
7
+ class LexicalJsxNode extends DecoratorNode {
8
+ __mdastNode;
9
+ __focusEmitter = voidEmitter();
10
+ __importStatement;
11
+ static getType() {
12
+ return "jsx";
13
+ }
14
+ static clone(node) {
15
+ return new LexicalJsxNode(structuredClone(node.__mdastNode), structuredClone(node.__importStatement), node.__key);
16
+ }
17
+ static importJSON(serializedNode) {
18
+ return $createLexicalJsxNode(serializedNode.mdastNode, serializedNode.importStatement);
19
+ }
20
+ constructor(mdastNode, importStatement, key) {
21
+ super(key);
22
+ this.__mdastNode = mdastNode;
23
+ this.__importStatement = importStatement;
24
+ }
25
+ getMdastNode() {
26
+ return this.__mdastNode;
27
+ }
28
+ getImportStatement() {
29
+ return this.__importStatement;
30
+ }
31
+ exportJSON() {
32
+ return {
33
+ mdastNode: this.getMdastNode(),
34
+ importStatement: this.getImportStatement(),
35
+ type: "jsx",
36
+ version: 1
37
+ };
38
+ }
39
+ createDOM() {
40
+ return document.createElement(this.__mdastNode.type === "mdxJsxTextElement" ? "span" : "div");
41
+ }
42
+ updateDOM() {
43
+ return false;
44
+ }
45
+ setMdastNode(mdastNode) {
46
+ this.getWritable().__mdastNode = mdastNode;
47
+ }
48
+ select = () => {
49
+ this.__focusEmitter.publish();
50
+ };
51
+ decorate(parentEditor, config) {
52
+ return /* @__PURE__ */ jsx(
53
+ JsxEditorContainer,
54
+ {
55
+ lexicalJsxNode: this,
56
+ config,
57
+ mdastNode: this.getMdastNode(),
58
+ parentEditor,
59
+ focusEmitter: this.__focusEmitter
60
+ }
61
+ );
62
+ }
63
+ isInline() {
64
+ return this.__mdastNode.type === "mdxJsxTextElement";
65
+ }
66
+ isKeyboardSelectable() {
67
+ return true;
68
+ }
69
+ }
70
+ function JsxEditorContainer(props) {
71
+ const { mdastNode } = props;
72
+ const jsxComponentDescriptors = useCellValue(jsxComponentDescriptors$);
73
+ const descriptor = jsxComponentDescriptors.find((descriptor2) => descriptor2.name === mdastNode.name) ?? jsxComponentDescriptors.find((descriptor2) => descriptor2.name === "*");
74
+ if (!descriptor) {
75
+ throw new Error(`No JSX descriptor found for ${mdastNode.name}`);
76
+ }
77
+ const Editor = descriptor.Editor;
78
+ return /* @__PURE__ */ jsx(
79
+ NestedEditorsContext.Provider,
80
+ {
81
+ value: {
82
+ config: props.config,
83
+ focusEmitter: props.focusEmitter,
84
+ mdastNode,
85
+ parentEditor: props.parentEditor,
86
+ lexicalNode: props.lexicalJsxNode
87
+ },
88
+ children: /* @__PURE__ */ jsx(Editor, { descriptor, mdastNode })
89
+ }
90
+ );
91
+ }
92
+ function $createLexicalJsxNode(mdastNode, importStatement) {
93
+ return new LexicalJsxNode(mdastNode, importStatement);
94
+ }
95
+ function $isLexicalJsxNode(node) {
96
+ return node instanceof LexicalJsxNode;
97
+ }
98
+ export {
99
+ $createLexicalJsxNode,
100
+ $isLexicalJsxNode,
101
+ JsxEditorContainer,
102
+ LexicalJsxNode
103
+ };
@@ -0,0 +1,27 @@
1
+ import { $isLexicalJsxNode } from "./LexicalJsxNode.js";
2
+ import { isMdastJsxNode } from "./index.js";
3
+ import { isHtmlTagName } from "./jsxTagName.js";
4
+ const LexicalJsxVisitor = {
5
+ testLexicalNode: $isLexicalJsxNode,
6
+ visitLexicalNode({ actions, mdastParent, lexicalNode }) {
7
+ function traverseNestedJsxNodes(node) {
8
+ if ("children" in node && node.children instanceof Array) {
9
+ node.children.forEach((child) => {
10
+ if (isMdastJsxNode(child) && !isHtmlTagName(child.name)) {
11
+ actions.registerReferredComponent(child.name);
12
+ }
13
+ traverseNestedJsxNodes(child);
14
+ });
15
+ }
16
+ }
17
+ const mdastNode = lexicalNode.getMdastNode();
18
+ const importStatement = lexicalNode.getImportStatement();
19
+ actions.registerReferredComponent(mdastNode.name, importStatement);
20
+ traverseNestedJsxNodes(mdastNode);
21
+ actions.appendToParent(mdastParent, mdastNode);
22
+ },
23
+ priority: -200
24
+ };
25
+ export {
26
+ LexicalJsxVisitor
27
+ };