@mdxeditor/editor 3.17.1 → 3.17.3

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
@@ -21,6 +21,7 @@ import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin.js';
21
21
  import { ListType } from '@lexical/list';
22
22
  import * as Mdast from 'mdast';
23
23
  import { MdxJsxAttribute } from 'mdast-util-mdx-jsx';
24
+ import { MdxJsxExpressionAttribute } from 'mdast-util-mdx-jsx';
24
25
  import { MdxJsxFlowElement } from 'mdast-util-mdx-jsx';
25
26
  import { MdxJsxTextElement } from 'mdast-util-mdx-jsx';
26
27
  import { Node as Node_2 } from 'unist';
@@ -691,6 +692,7 @@ export declare interface CreateImageNodeParameters {
691
692
  height?: number;
692
693
  title?: string;
693
694
  key?: NodeKey;
695
+ rest?: (MdxJsxAttribute | MdxJsxExpressionAttribute)[];
694
696
  src: string;
695
697
  }
696
698
 
@@ -1142,6 +1144,7 @@ export declare class FrontmatterNode extends DecoratorNode<JSX.Element> {
1142
1144
  getYaml(): string;
1143
1145
  setYaml(yaml: string): void;
1144
1146
  decorate(editor: LexicalEditor): JSX.Element;
1147
+ isKeyboardSelectable(): boolean;
1145
1148
  }
1146
1149
 
1147
1150
  /**
@@ -1276,6 +1279,7 @@ export declare class ImageNode extends DecoratorNode<JSX.Element> {
1276
1279
  /* Excluded from this release type: __title */
1277
1280
  /* Excluded from this release type: __width */
1278
1281
  /* Excluded from this release type: __height */
1282
+ /* Excluded from this release type: __rest */
1279
1283
  /* Excluded from this release type: getType */
1280
1284
  /* Excluded from this release type: clone */
1281
1285
  /* Excluded from this release type: importJSON */
@@ -1285,7 +1289,7 @@ export declare class ImageNode extends DecoratorNode<JSX.Element> {
1285
1289
  * Constructs a new {@link ImageNode} with the specified image parameters.
1286
1290
  * Use {@link $createImageNode} to construct one.
1287
1291
  */
1288
- constructor(src: string, altText: string, title: string | undefined, width?: 'inherit' | number, height?: 'inherit' | number, key?: NodeKey);
1292
+ constructor(src: string, altText: string, title: string | undefined, width?: 'inherit' | number, height?: 'inherit' | number, rest?: (MdxJsxAttribute | MdxJsxExpressionAttribute)[], key?: NodeKey);
1289
1293
  /* Excluded from this release type: exportJSON */
1290
1294
  /**
1291
1295
  * Sets the image dimensions
@@ -1298,10 +1302,11 @@ export declare class ImageNode extends DecoratorNode<JSX.Element> {
1298
1302
  getTitle(): string | undefined;
1299
1303
  getHeight(): 'inherit' | number;
1300
1304
  getWidth(): 'inherit' | number;
1305
+ getRest(): (MdxJsxAttribute | MdxJsxExpressionAttribute)[];
1301
1306
  setTitle(title: string | undefined): void;
1302
1307
  setSrc(src: string): void;
1303
1308
  setAltText(altText: string | undefined): void;
1304
- /* Excluded from this release type: hasExplicitDimensions */
1309
+ /* Excluded from this release type: shouldBeSerializedAsElement */
1305
1310
  /* Excluded from this release type: decorate */
1306
1311
  }
1307
1312
 
@@ -2558,6 +2563,7 @@ export declare type SerializedImageNode = Spread<{
2558
2563
  width?: number;
2559
2564
  height?: number;
2560
2565
  src: string;
2566
+ rest: (MdxJsxAttribute | MdxJsxExpressionAttribute)[];
2561
2567
  type: 'image';
2562
2568
  version: 1;
2563
2569
  }, SerializedLexicalNode>;
@@ -4,7 +4,7 @@ import { $isHeadingNode } from "@lexical/rich-text";
4
4
  import { $setBlocksType } from "@lexical/selection";
5
5
  import { $findMatchingParent, $wrapNodeInElement, $insertNodeToNearestRoot } from "@lexical/utils";
6
6
  import { Cell, withLatestFrom, Signal, filter, map, useCellValue, scan } from "@mdxeditor/gurx";
7
- import { createCommand, FORMAT_TEXT_COMMAND, $isRootOrShadowRoot, $getRoot, $setSelection, $getSelection, $insertNodes, SELECTION_CHANGE_COMMAND, COMMAND_PRIORITY_CRITICAL, DecoratorNode, $createParagraphNode, FOCUS_COMMAND, KEY_DOWN_COMMAND, $isDecoratorNode, BLUR_COMMAND, $isRangeSelection, ParagraphNode, TextNode, createEditor } from "lexical";
7
+ import { createCommand, FORMAT_TEXT_COMMAND, $isRootOrShadowRoot, $getRoot, $setSelection, $getSelection, $insertNodes, SELECTION_CHANGE_COMMAND, COMMAND_PRIORITY_CRITICAL, DecoratorNode, $createParagraphNode, FOCUS_COMMAND, BLUR_COMMAND, $isRangeSelection, ParagraphNode, TextNode, createEditor } from "lexical";
8
8
  import { gfmStrikethrough } from "micromark-extension-gfm-strikethrough";
9
9
  import { gfmStrikethroughFromMarkdown, gfmStrikethroughToMarkdown } from "mdast-util-gfm-strikethrough";
10
10
  import { mdxJsxToMarkdown, mdxJsxFromMarkdown } from "mdast-util-mdx-jsx";
@@ -12,7 +12,6 @@ import { mdxJsx } from "micromark-extension-mdx-jsx";
12
12
  import { mdxMd } from "micromark-extension-mdx-md";
13
13
  import { exportMarkdownFromLexical } from "../../exportMarkdownFromLexical.js";
14
14
  import { importMarkdownToLexical, MarkdownParseError, UnrecognizedMarkdownConstructError } from "../../importMarkdownToLexical.js";
15
- import { controlOrMeta } from "../../utils/detectMac.js";
16
15
  import { noop } from "../../utils/fp.js";
17
16
  import { GenericHTMLNode } from "./GenericHTMLNode.js";
18
17
  import { $createGenericHTMLNode, $isGenericHTMLNode, TYPE_NAME } from "./GenericHTMLNode.js";
@@ -284,37 +283,41 @@ const createRootEditorSubscription$ = Appender(rootEditorSubscriptions$, (r, sig
284
283
  },
285
284
  COMMAND_PRIORITY_CRITICAL
286
285
  );
287
- },
288
- // Fixes select all when frontmatter is present
289
- (rootEditor) => {
290
- return rootEditor.registerCommand(
291
- KEY_DOWN_COMMAND,
292
- (event) => {
293
- const { keyCode, ctrlKey, metaKey } = event;
294
- if (keyCode === 65 && controlOrMeta(metaKey, ctrlKey)) {
295
- let shouldOverride = false;
296
- rootEditor.getEditorState().read(() => {
297
- shouldOverride = $isDecoratorNode($getRoot().getFirstChild()) || $isDecoratorNode($getRoot().getLastChild());
298
- });
299
- if (shouldOverride) {
300
- event.preventDefault();
301
- event.stopImmediatePropagation();
302
- rootEditor.update(() => {
303
- var _a;
304
- const rootElement = rootEditor.getRootElement();
305
- (_a = window.getSelection()) == null ? void 0 : _a.selectAllChildren(rootElement);
306
- rootElement.focus({
307
- preventScroll: true
308
- });
309
- });
310
- return true;
311
- }
312
- }
313
- return false;
314
- },
315
- COMMAND_PRIORITY_CRITICAL
316
- );
317
286
  }
287
+ /*
288
+ // Fixes select all when frontmatter is present
289
+ (rootEditor) => {
290
+ return rootEditor.registerCommand<KeyboardEvent>(
291
+ KEY_DOWN_COMMAND,
292
+ (event) => {
293
+ const { keyCode, ctrlKey, metaKey } = event
294
+ if (keyCode === 65 && controlOrMeta(metaKey, ctrlKey)) {
295
+ let shouldOverride = false
296
+
297
+ rootEditor.getEditorState().read(() => {
298
+ shouldOverride = $isDecoratorNode($getRoot().getFirstChild()) || $isDecoratorNode($getRoot().getLastChild())
299
+ })
300
+
301
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
302
+ if (shouldOverride) {
303
+ event.preventDefault()
304
+ event.stopImmediatePropagation()
305
+ rootEditor.update(() => {
306
+ const rootElement = rootEditor.getRootElement() as HTMLDivElement
307
+ window.getSelection()?.selectAllChildren(rootElement)
308
+ rootElement.focus({
309
+ preventScroll: true
310
+ })
311
+ })
312
+ return true
313
+ }
314
+ }
315
+
316
+ return false
317
+ },
318
+ COMMAND_PRIORITY_CRITICAL
319
+ )
320
+ }*/
318
321
  ]);
319
322
  });
320
323
  const createActiveEditorSubscription$ = Appender(activeEditorSubscriptions$, (r, sig$) => {
@@ -59,6 +59,9 @@ class FrontmatterNode extends DecoratorNode {
59
59
  }
60
60
  );
61
61
  }
62
+ isKeyboardSelectable() {
63
+ return false;
64
+ }
62
65
  }
63
66
  function $createFrontmatterNode(yaml) {
64
67
  return new FrontmatterNode(yaml);
@@ -1,7 +1,7 @@
1
1
  import { realmPlugin } from "../../RealmWithPlugins.js";
2
2
  import { rootEditor$, createRootEditorSubscription$, addMdastExtension$, addSyntaxExtension$, addLexicalNode$, addImportVisitor$, addExportVisitor$, addToMarkdownExtension$ } from "../core/index.js";
3
3
  import { Cell, Action, withLatestFrom } from "@mdxeditor/gurx";
4
- import { $getRoot } from "lexical";
4
+ import { $getRoot, KEY_DOWN_COMMAND, $getSelection, $isRangeSelection, $isTextNode, COMMAND_PRIORITY_CRITICAL } from "lexical";
5
5
  import { frontmatterFromMarkdown, frontmatterToMarkdown } from "mdast-util-frontmatter";
6
6
  import { frontmatter } from "micromark-extension-frontmatter";
7
7
  import { $isFrontmatterNode, $createFrontmatterNode, FrontmatterNode } from "./FrontmatterNode.js";
@@ -52,7 +52,49 @@ const frontmatterPlugin = realmPlugin({
52
52
  [addLexicalNode$]: FrontmatterNode,
53
53
  [addImportVisitor$]: MdastFrontmatterVisitor,
54
54
  [addExportVisitor$]: LexicalFrontmatterVisitor,
55
- [addToMarkdownExtension$]: frontmatterToMarkdown("yaml")
55
+ [addToMarkdownExtension$]: frontmatterToMarkdown("yaml"),
56
+ [createRootEditorSubscription$]: (editor) => {
57
+ return editor.registerCommand(
58
+ KEY_DOWN_COMMAND,
59
+ (event) => {
60
+ let shouldPrevent = false;
61
+ editor.read(() => {
62
+ const selection = $getSelection();
63
+ if ($isRangeSelection(selection)) {
64
+ if (selection.isCollapsed() && selection.anchor.offset === 0 && selection.focus.offset === 0 && event.key === "Backspace") {
65
+ let node = selection.getNodes()[0];
66
+ if ($isTextNode(node)) {
67
+ node = node.getParent();
68
+ }
69
+ const prevSibling = node == null ? void 0 : node.getPreviousSibling();
70
+ if ($isFrontmatterNode(prevSibling)) {
71
+ shouldPrevent = true;
72
+ event.preventDefault();
73
+ }
74
+ } else {
75
+ const firstNode = selection.getNodes()[0];
76
+ if ($isFrontmatterNode(firstNode)) {
77
+ const yaml = firstNode.getYaml();
78
+ setTimeout(() => {
79
+ editor.update(
80
+ () => {
81
+ $getRoot().splice(0, 0, [$createFrontmatterNode(yaml)]);
82
+ },
83
+ { discrete: true }
84
+ );
85
+ });
86
+ }
87
+ }
88
+ }
89
+ });
90
+ if (shouldPrevent) {
91
+ return true;
92
+ }
93
+ return false;
94
+ },
95
+ COMMAND_PRIORITY_CRITICAL
96
+ );
97
+ }
56
98
  });
57
99
  }
58
100
  });
@@ -47,7 +47,7 @@ function LazyImage({
47
47
  }
48
48
  );
49
49
  }
50
- function ImageEditor({ src, title, alt, nodeKey, width, height }) {
50
+ function ImageEditor({ src, title, alt, nodeKey, width, height, rest }) {
51
51
  const [disableImageResize, disableImageSettingsButton, imagePreviewHandler, iconComponentFor, readOnly] = useCellValues(
52
52
  disableImageResize$,
53
53
  disableImageSettingsButton$,
@@ -200,14 +200,27 @@ function ImageEditor({ src, title, alt, nodeKey, width, height }) {
200
200
  };
201
201
  const draggable = $isNodeSelection(selection);
202
202
  const isFocused = isSelected;
203
+ const passedClassName = React__default.useMemo(() => {
204
+ if (rest.length === 0) {
205
+ return null;
206
+ }
207
+ const className = rest.find((attr) => attr.type === "mdxJsxAttribute" && (attr.name === "class" || attr.name === "className"));
208
+ if (className) {
209
+ return className.value;
210
+ }
211
+ return null;
212
+ }, [rest]);
203
213
  return imageSource !== null ? /* @__PURE__ */ React__default.createElement(React__default.Suspense, { fallback: null }, /* @__PURE__ */ React__default.createElement("div", { className: styles.imageWrapper, "data-editor-block-type": "image" }, /* @__PURE__ */ React__default.createElement("div", { draggable }, /* @__PURE__ */ React__default.createElement(
204
214
  LazyImage,
205
215
  {
206
216
  width,
207
217
  height,
208
- className: classNames({
209
- [styles.focusedImage]: isFocused
210
- }),
218
+ className: classNames(
219
+ {
220
+ [styles.focusedImage]: isFocused
221
+ },
222
+ passedClassName
223
+ ),
211
224
  src: imageSource,
212
225
  title: title ?? "",
213
226
  alt: alt ?? "",
@@ -20,7 +20,7 @@ class ImageNode extends DecoratorNode {
20
20
  * Constructs a new {@link ImageNode} with the specified image parameters.
21
21
  * Use {@link $createImageNode} to construct one.
22
22
  */
23
- constructor(src, altText, title, width, height, key) {
23
+ constructor(src, altText, title, width, height, rest, key) {
24
24
  super(key);
25
25
  /** @internal */
26
26
  __publicField(this, "__src");
@@ -32,11 +32,14 @@ class ImageNode extends DecoratorNode {
32
32
  __publicField(this, "__width");
33
33
  /** @internal */
34
34
  __publicField(this, "__height");
35
+ /** @internal */
36
+ __publicField(this, "__rest");
35
37
  this.__src = src;
36
38
  this.__title = title;
37
39
  this.__altText = altText;
38
40
  this.__width = width ? width : "inherit";
39
41
  this.__height = height ? height : "inherit";
42
+ this.__rest = rest ?? [];
40
43
  }
41
44
  /** @internal */
42
45
  static getType() {
@@ -44,17 +47,18 @@ class ImageNode extends DecoratorNode {
44
47
  }
45
48
  /** @internal */
46
49
  static clone(node) {
47
- return new ImageNode(node.__src, node.__altText, node.__title, node.__width, node.__height, node.__key);
50
+ return new ImageNode(node.__src, node.__altText, node.__title, node.__width, node.__height, node.__rest, node.__key);
48
51
  }
49
52
  /** @internal */
50
53
  static importJSON(serializedNode) {
51
- const { altText, title, src, width, height } = serializedNode;
54
+ const { altText, title, src, width, rest, height } = serializedNode;
52
55
  const node = $createImageNode({
53
56
  altText,
54
57
  title,
55
58
  src,
56
59
  height,
57
- width
60
+ width,
61
+ rest
58
62
  });
59
63
  return node;
60
64
  }
@@ -91,6 +95,7 @@ class ImageNode extends DecoratorNode {
91
95
  height: this.__height === "inherit" ? 0 : this.__height,
92
96
  width: this.__width === "inherit" ? 0 : this.__width,
93
97
  src: this.getSrc(),
98
+ rest: this.__rest,
94
99
  type: "image",
95
100
  version: 1
96
101
  };
@@ -132,6 +137,9 @@ class ImageNode extends DecoratorNode {
132
137
  getWidth() {
133
138
  return this.__width;
134
139
  }
140
+ getRest() {
141
+ return this.__rest;
142
+ }
135
143
  setTitle(title) {
136
144
  this.getWritable().__title = title;
137
145
  }
@@ -142,8 +150,8 @@ class ImageNode extends DecoratorNode {
142
150
  this.getWritable().__altText = altText ?? "";
143
151
  }
144
152
  /** @internal */
145
- hasExplicitDimensions() {
146
- return this.__width !== "inherit" || this.__height !== "inherit";
153
+ shouldBeSerializedAsElement() {
154
+ return this.__width !== "inherit" || this.__height !== "inherit" || this.__rest.length > 0;
147
155
  }
148
156
  /** @internal */
149
157
  decorate(_parentEditor) {
@@ -155,14 +163,15 @@ class ImageNode extends DecoratorNode {
155
163
  nodeKey: this.getKey(),
156
164
  width: this.__width,
157
165
  height: this.__height,
158
- alt: this.__altText
166
+ alt: this.__altText,
167
+ rest: this.__rest
159
168
  }
160
169
  );
161
170
  }
162
171
  }
163
172
  function $createImageNode(params) {
164
- const { altText, title, src, key, width, height } = params;
165
- return new ImageNode(src, altText, title, width, height, key);
173
+ const { altText, title, src, key, width, height, rest } = params;
174
+ return new ImageNode(src, altText, title, width, height, rest, key);
166
175
  }
167
176
  function $isImageNode(node) {
168
177
  return node instanceof ImageNode;
@@ -2,7 +2,7 @@ import { $isImageNode } from "./ImageNode.js";
2
2
  const LexicalImageVisitor = {
3
3
  testLexicalNode: $isImageNode,
4
4
  visitLexicalNode({ mdastParent, lexicalNode, actions }) {
5
- if (lexicalNode.hasExplicitDimensions()) {
5
+ if (lexicalNode.shouldBeSerializedAsElement()) {
6
6
  const img = new Image();
7
7
  if (lexicalNode.getHeight() !== "inherit") {
8
8
  img.height = lexicalNode.getHeight();
@@ -16,6 +16,13 @@ const LexicalImageVisitor = {
16
16
  if (lexicalNode.getTitle()) {
17
17
  img.title = lexicalNode.getTitle();
18
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
+ }
19
26
  actions.appendToParent(mdastParent, {
20
27
  type: "html",
21
28
  value: img.outerHTML.replace(/>$/, ` src="${lexicalNode.getSrc()}" />`)
@@ -64,12 +64,16 @@ const MdastJsxImageVisitor = {
64
64
  const title = getAttributeValue(mdastNode, "title");
65
65
  const height = getAttributeValue(mdastNode, "height");
66
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
+ });
67
70
  const image = $createImageNode({
68
71
  src,
69
72
  altText,
70
73
  title,
71
74
  width: width ? parseInt(width, 10) : void 0,
72
- height: height ? parseInt(height, 10) : void 0
75
+ height: height ? parseInt(height, 10) : void 0,
76
+ rest
73
77
  });
74
78
  if (lexicalParent.getType() === "root") {
75
79
  const paragraph = $createParagraphNode();
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "*.css"
12
12
  ],
13
13
  "type": "module",
14
- "version": "3.17.1",
14
+ "version": "3.17.3",
15
15
  "description": "React component for rich text markdown editing",
16
16
  "scripts": {
17
17
  "build": "vite build",