@mdxeditor/editor 3.28.0 → 3.29.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.
@@ -14,10 +14,14 @@ function exportLexicalTreeToMdast({
14
14
  }) {
15
15
  let unistRoot = null;
16
16
  const referredComponents = /* @__PURE__ */ new Set();
17
+ const knownImportSources = /* @__PURE__ */ new Map();
17
18
  visitors = visitors.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
18
19
  visit(root, null);
19
- function registerReferredComponent(componentName) {
20
+ function registerReferredComponent(componentName, importStatement) {
20
21
  referredComponents.add(componentName);
22
+ if (importStatement) {
23
+ knownImportSources.set(componentName, { ...importStatement });
24
+ }
21
25
  }
22
26
  function appendToParent(parentNode, node) {
23
27
  if (unistRoot === null) {
@@ -87,7 +91,7 @@ function exportLexicalTreeToMdast({
87
91
  const importsMap = /* @__PURE__ */ new Map();
88
92
  const defaultImportsMap = /* @__PURE__ */ new Map();
89
93
  for (const componentName of referredComponents) {
90
- const descriptor = jsxComponentDescriptors.find((descriptor2) => descriptor2.name === componentName) ?? jsxComponentDescriptors.find((descriptor2) => descriptor2.name === "*");
94
+ const descriptor = jsxComponentDescriptors.find((descriptor2) => descriptor2.name === componentName) ?? knownImportSources.get(componentName) ?? jsxComponentDescriptors.find((descriptor2) => descriptor2.name === "*");
91
95
  if (!descriptor) {
92
96
  throw new Error(`Component ${componentName} is used but not imported`);
93
97
  }
@@ -106,6 +110,21 @@ function exportLexicalTreeToMdast({
106
110
  }
107
111
  }
108
112
  }
113
+ if (!addImportStatements) {
114
+ for (const [path, names] of importsMap.entries()) {
115
+ const cleaned = names.filter((n) => knownImportSources.has(n));
116
+ if (cleaned.length > 0) {
117
+ importsMap.set(path, cleaned);
118
+ } else {
119
+ importsMap.delete(path);
120
+ }
121
+ }
122
+ for (const key of defaultImportsMap.keys()) {
123
+ if (!knownImportSources.has(key)) {
124
+ defaultImportsMap.delete(key);
125
+ }
126
+ }
127
+ }
109
128
  const imports = Array.from(importsMap).map(([source, componentNames]) => {
110
129
  return {
111
130
  type: "mdxjsEsm",
@@ -122,12 +141,10 @@ function exportLexicalTreeToMdast({
122
141
  );
123
142
  const typedRoot = unistRoot;
124
143
  const frontmatter = typedRoot.children.find((child) => child.type === "yaml");
125
- if (addImportStatements) {
126
- if (frontmatter) {
127
- typedRoot.children.splice(typedRoot.children.indexOf(frontmatter) + 1, 0, ...imports);
128
- } else {
129
- typedRoot.children.unshift(...imports);
130
- }
144
+ if (frontmatter) {
145
+ typedRoot.children.splice(typedRoot.children.indexOf(frontmatter) + 1, 0, ...imports);
146
+ } else {
147
+ typedRoot.children.unshift(...imports);
131
148
  }
132
149
  fixWrappingWhitespace(typedRoot, []);
133
150
  collapseNestedHtmlTags(typedRoot);
@@ -16,6 +16,32 @@ class UnrecognizedMarkdownConstructError extends Error {
16
16
  this.name = "UnrecognizedMarkdownConstructError";
17
17
  }
18
18
  }
19
+ function gatherMetadata(mdastNode) {
20
+ const importsMap = /* @__PURE__ */ new Map();
21
+ if (mdastNode.type !== "root") {
22
+ return {
23
+ importDeclarations: {}
24
+ };
25
+ }
26
+ const importStatements = mdastNode.children.filter((n) => n.type === "mdxjsEsm").filter((n) => n.value.startsWith("import "));
27
+ importStatements.forEach((imp) => {
28
+ var _a, _b;
29
+ (((_b = (_a = imp.data) == null ? void 0 : _a.estree) == null ? void 0 : _b.body) ?? []).forEach((declaration) => {
30
+ if (declaration.type !== "ImportDeclaration") {
31
+ return;
32
+ }
33
+ declaration.specifiers.forEach((specifier) => {
34
+ importsMap.set(specifier.local.name, {
35
+ source: `${declaration.source.value}`,
36
+ defaultExport: specifier.type === "ImportDefaultSpecifier"
37
+ });
38
+ });
39
+ });
40
+ });
41
+ return {
42
+ importDeclarations: Object.fromEntries(importsMap.entries())
43
+ };
44
+ }
19
45
  function importMarkdownToLexical({
20
46
  root,
21
47
  markdown,
@@ -49,6 +75,7 @@ function importMarkdownToLexical({
49
75
  function importMdastTreeToLexical({ root, mdastRoot, visitors, ...descriptors }) {
50
76
  const formattingMap = /* @__PURE__ */ new WeakMap();
51
77
  const styleMap = /* @__PURE__ */ new WeakMap();
78
+ const metaData = gatherMetadata(mdastRoot);
52
79
  visitors = visitors.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
53
80
  function visitChildren(mdastNode, lexicalParent) {
54
81
  if (!isParent(mdastNode)) {
@@ -83,6 +110,7 @@ function importMdastTreeToLexical({ root, mdastRoot, visitors, ...descriptors })
83
110
  lexicalParent,
84
111
  mdastParent,
85
112
  descriptors,
113
+ metaData,
86
114
  actions: {
87
115
  visitChildren,
88
116
  addAndStepInto(lexicalNode) {
package/dist/index.d.ts CHANGED
@@ -1411,6 +1411,11 @@ export declare interface ImportPoint {
1411
1411
  getType(): string;
1412
1412
  }
1413
1413
 
1414
+ export declare interface ImportStatement {
1415
+ source: string;
1416
+ defaultExport: boolean;
1417
+ }
1418
+
1414
1419
  /**
1415
1420
  * Contains the currently registered import vistors.
1416
1421
  * @group Core
@@ -1833,7 +1838,7 @@ export declare interface LexicalExportVisitor<LN extends LexicalNode, UN extends
1833
1838
  * @param componentName - the name of the component that has to be imported.
1834
1839
  * @see {@link JsxComponentDescriptor}
1835
1840
  */
1836
- registerReferredComponent(componentName: string): void;
1841
+ registerReferredComponent(componentName: string, importStatement?: ImportStatement): void;
1837
1842
  /**
1838
1843
  * visits the specified lexical node
1839
1844
  */
@@ -2027,6 +2032,10 @@ export declare interface MdastImportVisitor<UN extends Mdast.Nodes> {
2027
2032
  * The descriptors for composite nodes (jsx, directives, code blocks).
2028
2033
  */
2029
2034
  descriptors: Descriptors;
2035
+ /**
2036
+ * metaData: context data provided from the import visitor.
2037
+ */
2038
+ metaData: MetaData;
2030
2039
  /**
2031
2040
  * A set of convenience utilities that can be used to add nodes to the lexical tree.
2032
2041
  */
@@ -2221,6 +2230,13 @@ export declare interface MDXEditorProps {
2221
2230
  */
2222
2231
  export declare type MdxNodeType = MdastHTMLNode['type'];
2223
2232
 
2233
+ /**
2234
+ * Metadata that is provided to the visitors
2235
+ */
2236
+ declare interface MetaData {
2237
+ importDeclarations: Record<string, ImportStatement>;
2238
+ }
2239
+
2224
2240
  /**
2225
2241
  * A toolbar primitive that allows you to build an UI with multiple non-exclusive toggle groups, like the bold/italic/underline toggle.
2226
2242
  * @group Toolbar Primitives
@@ -2870,7 +2886,7 @@ export declare type Translation = (key: string, defaultValue: string, interpolat
2870
2886
  export declare const UndoRedo: default_2.FC;
2871
2887
 
2872
2888
  /**
2873
- * An error that gets thrown when the Markdown parsing encounters an node that has no corresponding {@link MdastImportVisitor}.
2889
+ * An error that gets thrown when the Markdown parsing encounters a node that has no corresponding {@link MdastImportVisitor}.
2874
2890
  * @group Markdown Processing
2875
2891
  */
2876
2892
  export declare class UnrecognizedMarkdownConstructError extends Error {
@@ -1,5 +1,5 @@
1
1
  import { $isTextNode } from "lexical";
2
- import { IS_ITALIC, IS_BOLD, IS_UNDERLINE, IS_STRIKETHROUGH, IS_SUPERSCRIPT, IS_SUBSCRIPT, IS_CODE } from "../../FormatConstants.js";
2
+ import { IS_UNDERLINE, IS_SUPERSCRIPT, IS_SUBSCRIPT, IS_ITALIC, IS_BOLD, IS_STRIKETHROUGH, IS_CODE } from "../../FormatConstants.js";
3
3
  function isMdastText(mdastNode) {
4
4
  return mdastNode.type === "text";
5
5
  }
@@ -45,18 +45,6 @@ const LexicalTextVisitor = {
45
45
  attributes: [{ type: "mdxJsxAttribute", name: "style", value: style }]
46
46
  });
47
47
  }
48
- if (prevFormat & format & IS_ITALIC) {
49
- localParentNode = actions.appendToParent(localParentNode, {
50
- type: "emphasis",
51
- children: []
52
- });
53
- }
54
- if (prevFormat & format & IS_BOLD) {
55
- localParentNode = actions.appendToParent(localParentNode, {
56
- type: "strong",
57
- children: []
58
- });
59
- }
60
48
  if (prevFormat & format & IS_UNDERLINE) {
61
49
  localParentNode = actions.appendToParent(localParentNode, {
62
50
  type: "mdxJsxTextElement",
@@ -65,12 +53,6 @@ const LexicalTextVisitor = {
65
53
  attributes: []
66
54
  });
67
55
  }
68
- if (prevFormat & format & IS_STRIKETHROUGH) {
69
- localParentNode = actions.appendToParent(localParentNode, {
70
- type: "delete",
71
- children: []
72
- });
73
- }
74
56
  if (prevFormat & format & IS_SUPERSCRIPT) {
75
57
  localParentNode = actions.appendToParent(localParentNode, {
76
58
  type: "mdxJsxTextElement",
@@ -87,18 +69,24 @@ const LexicalTextVisitor = {
87
69
  attributes: []
88
70
  });
89
71
  }
90
- if (format & IS_ITALIC && !(prevFormat & IS_ITALIC)) {
72
+ if (prevFormat & format & IS_ITALIC) {
91
73
  localParentNode = actions.appendToParent(localParentNode, {
92
74
  type: "emphasis",
93
75
  children: []
94
76
  });
95
77
  }
96
- if (format & IS_BOLD && !(prevFormat & IS_BOLD)) {
78
+ if (prevFormat & format & IS_BOLD) {
97
79
  localParentNode = actions.appendToParent(localParentNode, {
98
80
  type: "strong",
99
81
  children: []
100
82
  });
101
83
  }
84
+ if (prevFormat & format & IS_STRIKETHROUGH) {
85
+ localParentNode = actions.appendToParent(localParentNode, {
86
+ type: "delete",
87
+ children: []
88
+ });
89
+ }
102
90
  if (format & IS_UNDERLINE && !(prevFormat & IS_UNDERLINE)) {
103
91
  localParentNode = actions.appendToParent(localParentNode, {
104
92
  type: "mdxJsxTextElement",
@@ -107,12 +95,6 @@ const LexicalTextVisitor = {
107
95
  attributes: []
108
96
  });
109
97
  }
110
- if (format & IS_STRIKETHROUGH && !(prevFormat & IS_STRIKETHROUGH)) {
111
- localParentNode = actions.appendToParent(localParentNode, {
112
- type: "delete",
113
- children: []
114
- });
115
- }
116
98
  if (format & IS_SUPERSCRIPT && !(prevFormat & IS_SUPERSCRIPT)) {
117
99
  localParentNode = actions.appendToParent(localParentNode, {
118
100
  type: "mdxJsxTextElement",
@@ -129,6 +111,24 @@ const LexicalTextVisitor = {
129
111
  attributes: []
130
112
  });
131
113
  }
114
+ if (format & IS_ITALIC && !(prevFormat & IS_ITALIC)) {
115
+ localParentNode = actions.appendToParent(localParentNode, {
116
+ type: "emphasis",
117
+ children: []
118
+ });
119
+ }
120
+ if (format & IS_BOLD && !(prevFormat & IS_BOLD)) {
121
+ localParentNode = actions.appendToParent(localParentNode, {
122
+ type: "strong",
123
+ children: []
124
+ });
125
+ }
126
+ if (format & IS_STRIKETHROUGH && !(prevFormat & IS_STRIKETHROUGH)) {
127
+ localParentNode = actions.appendToParent(localParentNode, {
128
+ type: "delete",
129
+ children: []
130
+ });
131
+ }
132
132
  if (format & IS_CODE) {
133
133
  actions.appendToParent(localParentNode, {
134
134
  type: "inlineCode",
@@ -11,30 +11,36 @@ import { voidEmitter } from "../../utils/voidEmitter.js";
11
11
  import { useCellValue } from "@mdxeditor/gurx";
12
12
  import { jsxComponentDescriptors$ } from "../core/index.js";
13
13
  class LexicalJsxNode extends DecoratorNode {
14
- constructor(mdastNode, key) {
14
+ constructor(mdastNode, importStatement, key) {
15
15
  super(key);
16
16
  __publicField(this, "__mdastNode");
17
17
  __publicField(this, "__focusEmitter", voidEmitter());
18
+ __publicField(this, "__importStatement");
18
19
  __publicField(this, "select", () => {
19
20
  this.__focusEmitter.publish();
20
21
  });
21
22
  this.__mdastNode = mdastNode;
23
+ this.__importStatement = importStatement;
22
24
  }
23
25
  static getType() {
24
26
  return "jsx";
25
27
  }
26
28
  static clone(node) {
27
- return new LexicalJsxNode(structuredClone(node.__mdastNode), node.__key);
29
+ return new LexicalJsxNode(structuredClone(node.__mdastNode), structuredClone(node.__importStatement), node.__key);
28
30
  }
29
31
  static importJSON(serializedNode) {
30
- return $createLexicalJsxNode(serializedNode.mdastNode);
32
+ return $createLexicalJsxNode(serializedNode.mdastNode, serializedNode.importStatement);
31
33
  }
32
34
  getMdastNode() {
33
35
  return this.__mdastNode;
34
36
  }
37
+ getImportStatement() {
38
+ return this.__importStatement;
39
+ }
35
40
  exportJSON() {
36
41
  return {
37
42
  mdastNode: this.getMdastNode(),
43
+ importStatement: this.getImportStatement(),
38
44
  type: "jsx",
39
45
  version: 1
40
46
  };
@@ -89,8 +95,8 @@ function JsxEditorContainer(props) {
89
95
  /* @__PURE__ */ React__default.createElement(Editor, { descriptor, mdastNode })
90
96
  );
91
97
  }
92
- function $createLexicalJsxNode(mdastNode) {
93
- return new LexicalJsxNode(mdastNode);
98
+ function $createLexicalJsxNode(mdastNode, importStatement) {
99
+ return new LexicalJsxNode(mdastNode, importStatement);
94
100
  }
95
101
  function $isLexicalJsxNode(node) {
96
102
  return node instanceof LexicalJsxNode;
@@ -15,7 +15,8 @@ const LexicalJsxVisitor = {
15
15
  }
16
16
  }
17
17
  const mdastNode = lexicalNode.getMdastNode();
18
- actions.registerReferredComponent(mdastNode.name);
18
+ const importStatement = lexicalNode.getImportStatement();
19
+ actions.registerReferredComponent(mdastNode.name, importStatement);
19
20
  traverseNestedJsxNodes(mdastNode);
20
21
  actions.appendToParent(mdastParent, mdastNode);
21
22
  },
@@ -8,15 +8,17 @@ const MdastMdxJsxElementVisitor = {
8
8
  }
9
9
  return false;
10
10
  },
11
- visitNode({ lexicalParent, mdastNode, descriptors: { jsxComponentDescriptors } }) {
11
+ visitNode({ lexicalParent, mdastNode, descriptors: { jsxComponentDescriptors }, metaData }) {
12
12
  const descriptor = jsxComponentDescriptors.find((descriptor2) => descriptor2.name === mdastNode.name) ?? jsxComponentDescriptors.find((descriptor2) => descriptor2.name === "*");
13
13
  if ((descriptor == null ? void 0 : descriptor.kind) === "text" && mdastNode.type === "mdxJsxFlowElement") {
14
14
  const patchedNode = { ...mdastNode, type: "mdxJsxTextElement" };
15
15
  const paragraph = $createParagraphNode();
16
- paragraph.append($createLexicalJsxNode(patchedNode));
16
+ paragraph.append($createLexicalJsxNode(patchedNode, mdastNode.name ? metaData.importDeclarations[mdastNode.name] : void 0));
17
17
  lexicalParent.append(paragraph);
18
18
  } else {
19
- lexicalParent.append($createLexicalJsxNode(mdastNode));
19
+ lexicalParent.append(
20
+ $createLexicalJsxNode(mdastNode, mdastNode.name ? metaData.importDeclarations[mdastNode.name] : void 0)
21
+ );
20
22
  }
21
23
  },
22
24
  priority: -200
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "*.css"
12
12
  ],
13
13
  "type": "module",
14
- "version": "3.28.0",
14
+ "version": "3.29.0",
15
15
  "description": "React component for rich text markdown editing",
16
16
  "scripts": {
17
17
  "build": "vite build",