@mdxeditor/editor 3.52.1 → 3.52.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.
@@ -9,10 +9,11 @@ const AdmonitionDirectiveDescriptor = {
9
9
  return ADMONITION_TYPES.includes(node.name);
10
10
  },
11
11
  Editor({ mdastNode }) {
12
+ var _a;
12
13
  const {
13
14
  config: { theme }
14
15
  } = useNestedEditorContext();
15
- return /* @__PURE__ */ React__default.createElement("div", { className: theme.admonition[mdastNode.name] }, /* @__PURE__ */ React__default.createElement(
16
+ return /* @__PURE__ */ React__default.createElement("div", { className: (_a = theme.admonition) == null ? void 0 : _a[mdastNode.name] }, /* @__PURE__ */ React__default.createElement(
16
17
  NestedLexicalEditor,
17
18
  {
18
19
  block: true,
@@ -212,7 +212,7 @@ function fixWrappingWhitespace(node, parentChain) {
212
212
  if (node.type === "strong" || node.type === "emphasis") {
213
213
  const lastChild = node.children.at(-1);
214
214
  if ((lastChild == null ? void 0 : lastChild.type) === "text") {
215
- const trailingWhitespace = lastChild.value.match(TRAILING_WHITESPACE_REGEXP);
215
+ const trailingWhitespace = TRAILING_WHITESPACE_REGEXP.exec(lastChild.value);
216
216
  if (trailingWhitespace) {
217
217
  lastChild.value = lastChild.value.replace(TRAILING_WHITESPACE_REGEXP, "");
218
218
  const parent = parentChain.at(-1);
@@ -227,7 +227,7 @@ function fixWrappingWhitespace(node, parentChain) {
227
227
  }
228
228
  const firstChild = node.children.at(0);
229
229
  if ((firstChild == null ? void 0 : firstChild.type) === "text") {
230
- const leadingWhitespace = firstChild.value.match(LEADING_WHITESPACE_REGEXP);
230
+ const leadingWhitespace = LEADING_WHITESPACE_REGEXP.exec(firstChild.value);
231
231
  if (leadingWhitespace) {
232
232
  firstChild.value = firstChild.value.replace(LEADING_WHITESPACE_REGEXP, "");
233
233
  const parent = parentChain.at(-1);
@@ -98,7 +98,7 @@ function importMdastTreeToLexical({ root, mdastRoot, visitors, ...descriptors })
98
98
  if (!visitor) {
99
99
  try {
100
100
  throw new UnrecognizedMarkdownConstructError(`Unsupported markdown syntax: ${toMarkdown(mdastNode)}`);
101
- } catch (e) {
101
+ } catch (_e) {
102
102
  throw new UnrecognizedMarkdownConstructError(
103
103
  `Parsing of the following markdown structure failed: ${JSON.stringify({
104
104
  type: mdastNode.type,
package/dist/index.d.ts CHANGED
@@ -424,7 +424,7 @@ export declare const ChangeAdmonitionType: () => JSX_2.Element;
424
424
  * See {@link ConditionalContents} for an example on how to display the dropdown only when a code block is in focus.
425
425
  * @group Toolbar Components
426
426
  */
427
- export declare const ChangeCodeMirrorLanguage: () => JSX_2.Element;
427
+ export declare const ChangeCodeMirrorLanguage: () => JSX_2.Element | null;
428
428
 
429
429
  export declare type ClickLinkCallback = (url: string) => void;
430
430
 
@@ -548,11 +548,12 @@ export declare class CodeBlockNode extends DecoratorNode<JSX.Element> {
548
548
  };
549
549
  static getType(): string;
550
550
  static clone(node: CodeBlockNode): CodeBlockNode;
551
+ afterCloneFrom(prevNode: this): void;
551
552
  static importJSON(serializedNode: SerializedCodeBlockNode): CodeBlockNode;
552
553
  static importDOM(): DOMConversionMap;
553
554
  constructor(code: string, language: string, meta: string, key?: NodeKey);
554
555
  exportJSON(): SerializedCodeBlockNode;
555
- createDOM(_config: EditorConfig): HTMLDivElement;
556
+ createDOM(_config: EditorConfig, _editor: LexicalEditor): HTMLDivElement;
556
557
  updateDOM(): false;
557
558
  getCode(): string;
558
559
  getMeta(): string;
@@ -573,11 +574,11 @@ export declare const codeBlockPlugin: (params?: {
573
574
  /**
574
575
  * Pass an array of {@link CodeBlockEditorDescriptor} to register custom code block editors.
575
576
  */
576
- codeBlockEditorDescriptors?: CodeBlockEditorDescriptor[] | undefined;
577
+ codeBlockEditorDescriptors?: CodeBlockEditorDescriptor[];
577
578
  /**
578
579
  * The default language to use when creating a new code block if no language is passed.
579
580
  */
580
- defaultCodeBlockLanguage?: string | undefined;
581
+ defaultCodeBlockLanguage?: string;
581
582
  } | undefined) => RealmPlugin;
582
583
 
583
584
  /**
@@ -604,13 +605,13 @@ export declare const codeMirrorPlugin: (params?: {
604
605
  /**
605
606
  * Optional, additional CodeMirror extensions to load in the diff/source mode.
606
607
  */
607
- codeMirrorExtensions?: Extension_2[] | undefined;
608
+ codeMirrorExtensions?: Extension_2[];
608
609
  /**
609
610
  * Whether or not to try to dynamically load the code block language support.
610
611
  * Disable if you want to manually pass the supported languages.
611
612
  * @group CodeMirror
612
613
  */
613
- autoLoadLanguageSupport?: boolean | undefined;
614
+ autoLoadLanguageSupport?: boolean;
614
615
  } | undefined) => RealmPlugin;
615
616
 
616
617
  /**
@@ -887,7 +888,7 @@ export declare const DialogButton: default_2.ForwardRefExoticComponent<{
887
888
  /**
888
889
  * The autocomplete suggestions to show in the dialog input.
889
890
  */
890
- autocompleteSuggestions?: string[] | undefined;
891
+ autocompleteSuggestions?: string[];
891
892
  /**
892
893
  * The callback to call when the dialog is submitted. The callback receives the value of the text input as a parameter.
893
894
  */
@@ -924,21 +925,21 @@ export declare const diffSourcePlugin: (params?: {
924
925
  * The initial view mode of the editor.
925
926
  * @default 'rich-text'
926
927
  */
927
- viewMode?: ViewMode | undefined;
928
+ viewMode?: ViewMode;
928
929
  /**
929
930
  * The markdown to show in the diff editor.
930
931
  * @default ''
931
932
  */
932
- diffMarkdown?: string | undefined;
933
+ diffMarkdown?: string;
933
934
  /**
934
935
  * Optional, additional CodeMirror extensions to load in the diff/source mode.
935
936
  */
936
- codeMirrorExtensions?: Extension_2[] | undefined;
937
+ codeMirrorExtensions?: Extension_2[];
937
938
  /**
938
939
  * Set the diff editor to read-only.
939
940
  * @default false
940
941
  */
941
- readOnlyDiff?: boolean | undefined;
942
+ readOnlyDiff?: boolean;
942
943
  } | undefined) => RealmPlugin;
943
944
 
944
945
  /**
@@ -1072,7 +1073,7 @@ export declare const directivesPlugin: (params?: {
1072
1073
  * Set this option to display unknown text-directives as normal text nodes.
1073
1074
  * This is handy when colons are used to separate words, e.g. in german "Schüler:in"
1074
1075
  */
1075
- escapeUnknownTextDirectives?: boolean | undefined;
1076
+ escapeUnknownTextDirectives?: boolean;
1076
1077
  } | undefined) => RealmPlugin;
1077
1078
 
1078
1079
  /**
@@ -1362,7 +1363,7 @@ export declare const headingsPlugin: (params?: {
1362
1363
  * Allows you to limit the headings used in the editor. Affects the block type dropdown and the keyboard shortcuts.
1363
1364
  * @default [1, 2, 3, 4, 5, 6]
1364
1365
  */
1365
- allowedHeadingLevels?: readonly HEADING_LEVEL[] | undefined;
1366
+ allowedHeadingLevels?: readonly HEADING_LEVEL[];
1366
1367
  } | undefined) => RealmPlugin;
1367
1368
 
1368
1369
  /**
@@ -1412,6 +1413,7 @@ export declare class ImageNode extends DecoratorNode<JSX.Element> {
1412
1413
  /* Excluded from this release type: __rest */
1413
1414
  /* Excluded from this release type: getType */
1414
1415
  /* Excluded from this release type: clone */
1416
+ /* Excluded from this release type: afterCloneFrom */
1415
1417
  /* Excluded from this release type: importJSON */
1416
1418
  /* Excluded from this release type: exportDOM */
1417
1419
  /* Excluded from this release type: importDOM */
@@ -1451,15 +1453,15 @@ export declare const imagePlaceholder$: NodeRef< FC<{}> | null>;
1451
1453
  * @group Image
1452
1454
  */
1453
1455
  export declare const imagePlugin: (params?: {
1454
- imageUploadHandler?: ImageUploadHandler | undefined;
1455
- imageAutocompleteSuggestions?: string[] | undefined;
1456
- disableImageResize?: boolean | undefined;
1457
- disableImageSettingsButton?: boolean | undefined;
1458
- allowSetImageDimensions?: boolean | undefined;
1459
- imagePreviewHandler?: ImagePreviewHandler | undefined;
1460
- ImageDialog?: FC<{}> | (() => JSX.Element) | undefined;
1461
- EditImageToolbar?: FC<{}> | (() => JSX.Element) | undefined;
1462
- imagePlaceholder?: (() => JSX.Element) | null | undefined;
1456
+ imageUploadHandler?: ImageUploadHandler;
1457
+ imageAutocompleteSuggestions?: string[];
1458
+ disableImageResize?: boolean;
1459
+ disableImageSettingsButton?: boolean;
1460
+ allowSetImageDimensions?: boolean;
1461
+ imagePreviewHandler?: ImagePreviewHandler;
1462
+ ImageDialog?: (() => JSX.Element) | React.FC;
1463
+ EditImageToolbar?: (() => JSX.Element) | React.FC;
1464
+ imagePlaceholder?: (() => JSX.Element) | null;
1463
1465
  } | undefined) => RealmPlugin;
1464
1466
 
1465
1467
  /**
@@ -1577,9 +1579,9 @@ export declare const insertDecoratorNode$: NodeRef<() => DecoratorNode<unknown>>
1577
1579
  * @group Directive
1578
1580
  */
1579
1581
  export declare const insertDirective$: NodeRef<{
1580
- type: Directives['type'];
1582
+ type: Directives["type"];
1581
1583
  name: string;
1582
- attributes?: Directives['attributes'];
1584
+ attributes?: Directives["attributes"];
1583
1585
  }>;
1584
1586
 
1585
1587
  /**
@@ -1620,15 +1622,15 @@ export declare type InsertImageParameters = FileImageParameters | SrcImageParame
1620
1622
  * @group JSX
1621
1623
  */
1622
1624
  export declare const insertJsx$: NodeRef<{
1623
- kind: 'text';
1625
+ kind: "text";
1624
1626
  name: string;
1625
1627
  props: JsxProperties;
1626
- children?: Mdast.PhrasingContent[] | undefined;
1628
+ children?: MdxJsxTextElement["children"];
1627
1629
  } | {
1628
- kind: 'flow';
1630
+ kind: "flow";
1629
1631
  name: string;
1630
1632
  props: JsxProperties;
1631
- children?: (Mdast.BlockContent | Mdast.DefinitionContent)[] | undefined;
1633
+ children?: MdxJsxFlowElement["children"];
1632
1634
  }>;
1633
1635
 
1634
1636
  /**
@@ -1666,11 +1668,11 @@ export declare const insertTable$: NodeRef<{
1666
1668
  /**
1667
1669
  * The number of rows of the table.
1668
1670
  */
1669
- rows?: number | undefined;
1671
+ rows?: number;
1670
1672
  /**
1671
1673
  * The number of columns of the table.
1672
1674
  */
1673
- columns?: number | undefined;
1675
+ columns?: number;
1674
1676
  }>;
1675
1677
 
1676
1678
  /**
@@ -1968,23 +1970,23 @@ export declare const linkDialogPlugin: (params?: {
1968
1970
  /**
1969
1971
  * If passed, the link dialog will be rendered using this component instead of the default one.
1970
1972
  */
1971
- LinkDialog?: (() => JSX.Element) | undefined;
1973
+ LinkDialog?: () => JSX.Element;
1972
1974
  /**
1973
1975
  * If passed, the link input field will autocomplete using the published suggestions.
1974
1976
  */
1975
- linkAutocompleteSuggestions?: string[] | undefined;
1977
+ linkAutocompleteSuggestions?: string[];
1976
1978
  /**
1977
1979
  * If set, clicking on the link in the preview popup will call this callback instead of opening the link.
1978
1980
  */
1979
- onClickLinkCallback?: ClickLinkCallback | undefined;
1981
+ onClickLinkCallback?: ClickLinkCallback;
1980
1982
  /**
1981
1983
  * Invoked when a link is clicked in read-only mode
1982
1984
  */
1983
- onReadOnlyClickLinkCallback?: ReadOnlyClickLinkCallback | undefined;
1985
+ onReadOnlyClickLinkCallback?: ReadOnlyClickLinkCallback;
1984
1986
  /**
1985
1987
  * If true, show the "Link title" field in link dialogs (this sets mouseover text, NOT anchor text)
1986
1988
  */
1987
- showLinkTitleField?: boolean | undefined;
1989
+ showLinkTitleField?: boolean;
1988
1990
  } | undefined) => RealmPlugin;
1989
1991
 
1990
1992
  /**
@@ -2002,12 +2004,12 @@ export declare const linkPlugin: (params?: {
2002
2004
  * An optional function to validate the URL of a link.
2003
2005
  * By default, no validation is performed.
2004
2006
  */
2005
- validateUrl?: default_2.ComponentProps<typeof LinkPlugin>['validateUrl'];
2007
+ validateUrl?: default_2.ComponentProps<typeof LinkPlugin>["validateUrl"];
2006
2008
  /**
2007
2009
  * Whether to disable the auto-linking of URLs and email addresses.
2008
2010
  * @default false
2009
2011
  */
2010
- disableAutoLink?: boolean | undefined;
2012
+ disableAutoLink?: boolean;
2011
2013
  } | undefined) => RealmPlugin;
2012
2014
 
2013
2015
  /**
@@ -2237,7 +2239,7 @@ export declare interface MDXEditorMethods {
2237
2239
  /**
2238
2240
  * Sets focus on input
2239
2241
  */
2240
- focus: (callbackFn?: (() => void) | undefined, opts?: {
2242
+ focus: (callbackFn?: () => void, opts?: {
2241
2243
  defaultSelection?: 'rootStart' | 'rootEnd';
2242
2244
  preventScroll?: boolean;
2243
2245
  }) => void;
@@ -2781,7 +2783,7 @@ export declare const Select: <T extends string>(props: {
2781
2783
  items: ({
2782
2784
  label: string | JSX.Element;
2783
2785
  value: T;
2784
- } | 'separator')[];
2786
+ } | "separator")[];
2785
2787
  }) => JSX_2.Element;
2786
2788
 
2787
2789
  /* Excluded from this release type: SelectButtonTrigger */
@@ -2875,7 +2877,7 @@ export declare const showLinkTitleField$: NodeRef<boolean>;
2875
2877
  * See {@link ConditionalContents} for an example on how to display the dropdown only when a sandpack editor is in focus.
2876
2878
  * @group Toolbar Components
2877
2879
  */
2878
- export declare const ShowSandpackInfo: () => JSX_2.Element;
2880
+ export declare const ShowSandpackInfo: () => JSX_2.Element | null;
2879
2881
 
2880
2882
  /**
2881
2883
  * A toolbar primitive that allows you to build an UI with multiple exclusive toggle groups, like the list type toggle.
@@ -2887,8 +2889,8 @@ export declare const SingleChoiceToggleGroup: <T extends string>({ value, onChan
2887
2889
  value: T;
2888
2890
  contents: default_2.ReactNode;
2889
2891
  }[];
2890
- onChange: (value: T | '') => void;
2891
- value: T | '';
2892
+ onChange: (value: T | "") => void;
2893
+ value: T | "";
2892
2894
  ggClassName?: string;
2893
2895
  className?: string;
2894
2896
  }) => JSX_2.Element;
@@ -3036,11 +3038,11 @@ export declare const toolbarPlugin: (params?: {
3036
3038
  /**
3037
3039
  * The class name to apply to the toolbar element
3038
3040
  */
3039
- toolbarClassName?: string | undefined;
3041
+ toolbarClassName?: string;
3040
3042
  /**
3041
3043
  * Controls the position of the toolbar (top by default)
3042
3044
  */
3043
- toolbarPosition?: "top" | "bottom" | undefined;
3045
+ toolbarPosition?: "top" | "bottom";
3044
3046
  } | undefined) => RealmPlugin;
3045
3047
 
3046
3048
  /* Excluded from this release type: ToolbarToggleItem */
@@ -45,6 +45,13 @@ class CodeBlockNode extends DecoratorNode {
45
45
  static clone(node) {
46
46
  return new CodeBlockNode(node.__code, node.__language, node.__meta, node.__key);
47
47
  }
48
+ afterCloneFrom(prevNode) {
49
+ super.afterCloneFrom(prevNode);
50
+ this.__code = prevNode.__code;
51
+ this.__meta = prevNode.__meta;
52
+ this.__language = prevNode.__language;
53
+ this.__focusEmitter = voidEmitter();
54
+ }
48
55
  static importJSON(serializedNode) {
49
56
  const { code, meta, language } = serializedNode;
50
57
  return $createCodeBlockNode({
@@ -73,7 +80,7 @@ class CodeBlockNode extends DecoratorNode {
73
80
  };
74
81
  }
75
82
  // View
76
- createDOM(_config) {
83
+ createDOM(_config, _editor) {
77
84
  return document.createElement("div");
78
85
  }
79
86
  updateDOM() {
@@ -145,9 +152,7 @@ const CodeBlockEditorContainer = (props) => {
145
152
  const codeBlockEditorDescriptors = useCellValue(codeBlockEditorDescriptors$);
146
153
  const defaultCodeBlockLanguage = useCellValue(defaultCodeBlockLanguage$);
147
154
  let descriptor = codeBlockEditorDescriptors.sort((a, b) => b.priority - a.priority).find((descriptor2) => descriptor2.match(props.language || "", props.meta || ""));
148
- if (!descriptor) {
149
- descriptor = codeBlockEditorDescriptors.find((descriptor2) => descriptor2.match(defaultCodeBlockLanguage || "", props.meta || ""));
150
- }
155
+ descriptor ?? (descriptor = codeBlockEditorDescriptors.find((descriptor2) => descriptor2.match(defaultCodeBlockLanguage || "", props.meta || "")));
151
156
  if (!descriptor) {
152
157
  throw new Error(`No CodeBlockEditor registered for language=${props.language} meta=${props.meta}`);
153
158
  }
@@ -164,10 +169,10 @@ function $isCodeBlockNode(node) {
164
169
  }
165
170
  function $convertPreElement(element) {
166
171
  const preElement = element;
167
- const code = preElement.textContent ?? "";
172
+ const code = preElement.textContent;
168
173
  const classAttribute = element.getAttribute("class") ?? "";
169
174
  const dataLanguageAttribute = element.getAttribute("data-language") ?? "";
170
- const languageMatch = classAttribute.match(/language-(\w+)/);
175
+ const languageMatch = /language-(\w+)/.exec(classAttribute);
171
176
  const language = languageMatch ? languageMatch[1] : dataLanguageAttribute;
172
177
  const meta = preElement.getAttribute("data-meta") ?? "";
173
178
  return {
@@ -66,7 +66,7 @@ const CodeMirrorEditor = ({ language, nodeKey, code, focusEmitter }) => {
66
66
  try {
67
67
  const languageSupport = await languageData.load();
68
68
  extensions.push(languageSupport.extension);
69
- } catch (e) {
69
+ } catch (_e) {
70
70
  console.warn("failed to load language support for", language);
71
71
  }
72
72
  }
@@ -46,7 +46,7 @@ const codeMirrorPlugin = realmPlugin({
46
46
  function buildCodeBlockDescriptor(codeBlockLanguages) {
47
47
  return {
48
48
  match(language, meta) {
49
- return Boolean(Object.hasOwn(codeBlockLanguages, language ?? "")) && !meta;
49
+ return Object.hasOwn(codeBlockLanguages, language ?? "") && !meta;
50
50
  },
51
51
  priority: 1,
52
52
  Editor: CodeMirrorEditor
@@ -70,9 +70,7 @@ const currentSelection$ = Cell(null, (r) => {
70
70
  const parent = e.getParent();
71
71
  return parent !== null && $isRootOrShadowRoot(parent);
72
72
  });
73
- if (element === null) {
74
- element = anchorNode.getTopLevelElementOrThrow();
75
- }
73
+ element ?? (element = anchorNode.getTopLevelElementOrThrow());
76
74
  const elementKey = element.getKey();
77
75
  const elementDOM = theEditor.getElementByKey(elementKey);
78
76
  if (elementDOM !== null) {
@@ -6,31 +6,31 @@ import { controlOrMeta } from "../../utils/detectMac.js";
6
6
  import { createRootEditorSubscription$, convertSelectionToNode$, addExportVisitor$, addLexicalNode$, addImportVisitor$, addActivePlugin$ } from "../core/index.js";
7
7
  import { LexicalHeadingVisitor } from "./LexicalHeadingVisitor.js";
8
8
  import { MdastHeadingVisitor } from "./MdastHeadingVisitor.js";
9
- const FORMATTING_KEYS = [48, 49, 50, 51, 52, 53, 54];
9
+ const FORMATTING_KEYS = ["Digit0", "Digit1", "Digit2", "Digit3", "Digit4", "Digit5", "Digit6"];
10
10
  const ALL_HEADING_LEVELS = [1, 2, 3, 4, 5, 6];
11
11
  const CODE_TO_HEADING_LEVEL_MAP = {
12
- 49: 1,
13
- 50: 2,
14
- 51: 3,
15
- 52: 4,
16
- 53: 5,
17
- 54: 6
12
+ Digit1: 1,
13
+ Digit2: 2,
14
+ Digit3: 3,
15
+ Digit4: 4,
16
+ Digit5: 5,
17
+ Digit6: 6
18
18
  };
19
19
  const allowedHeadingLevels$ = Cell(ALL_HEADING_LEVELS, (r) => {
20
20
  r.pub(createRootEditorSubscription$, (theRootEditor) => {
21
21
  return theRootEditor.registerCommand(
22
22
  KEY_DOWN_COMMAND,
23
23
  (event) => {
24
- const { keyCode, ctrlKey, metaKey, altKey } = event;
25
- if (FORMATTING_KEYS.includes(keyCode) && controlOrMeta(metaKey, ctrlKey) && altKey) {
24
+ const { code, ctrlKey, metaKey, altKey } = event;
25
+ if (FORMATTING_KEYS.includes(code) && controlOrMeta(metaKey, ctrlKey) && altKey) {
26
26
  event.preventDefault();
27
27
  theRootEditor.update(() => {
28
- if (keyCode === 48) {
28
+ if (code === "Digit0") {
29
29
  r.pub(convertSelectionToNode$, () => $createParagraphNode());
30
30
  } else {
31
31
  const allowedHeadingLevels = r.getValue(allowedHeadingLevels$);
32
- const requestedHeadingLevel = CODE_TO_HEADING_LEVEL_MAP[keyCode];
33
- if (!allowedHeadingLevels.includes(requestedHeadingLevel)) {
32
+ const requestedHeadingLevel = CODE_TO_HEADING_LEVEL_MAP[code];
33
+ if (allowedHeadingLevels.includes(requestedHeadingLevel)) {
34
34
  r.pub(convertSelectionToNode$, () => $createHeadingNode(`h${requestedHeadingLevel}`));
35
35
  }
36
36
  }
@@ -39,7 +39,7 @@ function EditImageToolbar(props) {
39
39
  openEditImageDialog({
40
40
  nodeKey,
41
41
  initialValues: {
42
- src: !initialImagePath ? imageSource : initialImagePath,
42
+ src: initialImagePath ?? imageSource,
43
43
  title,
44
44
  altText: alt,
45
45
  width: parseImageDimension(width),
@@ -37,8 +37,8 @@ class ImageNode extends DecoratorNode {
37
37
  this.__src = src;
38
38
  this.__title = title;
39
39
  this.__altText = altText;
40
- this.__width = width ? width : "inherit";
41
- this.__height = height ? height : "inherit";
40
+ this.__width = width ?? "inherit";
41
+ this.__height = height ?? "inherit";
42
42
  this.__rest = rest ?? [];
43
43
  }
44
44
  /** @internal */
@@ -50,6 +50,16 @@ class ImageNode extends DecoratorNode {
50
50
  return new ImageNode(node.__src, node.__altText, node.__title, node.__width, node.__height, node.__rest, node.__key);
51
51
  }
52
52
  /** @internal */
53
+ afterCloneFrom(prevNode) {
54
+ super.afterCloneFrom(prevNode);
55
+ this.__src = prevNode.__src;
56
+ this.__altText = prevNode.__altText;
57
+ this.__title = prevNode.__title;
58
+ this.__width = prevNode.__width;
59
+ this.__height = prevNode.__height;
60
+ this.__rest = prevNode.__rest;
61
+ }
62
+ /** @internal */
53
63
  static importJSON(serializedNode) {
54
64
  const { altText, title, src, width, rest, height } = serializedNode;
55
65
  const node = $createImageNode({
@@ -109,7 +119,7 @@ class ImageNode extends DecoratorNode {
109
119
  writable.__height = height;
110
120
  }
111
121
  /** @internal */
112
- createDOM(config) {
122
+ createDOM(config, _editor) {
113
123
  const span = document.createElement("span");
114
124
  const theme = config.theme;
115
125
  const className = theme.image;
@@ -35,7 +35,7 @@ function ImageResizer({
35
35
  startY: 0
36
36
  });
37
37
  const editorRootElement = editor.getRootElement();
38
- const maxWidthContainer = maxWidth ? maxWidth : editorRootElement !== null ? editorRootElement.getBoundingClientRect().width - 20 : 100;
38
+ const maxWidthContainer = maxWidth ?? (editorRootElement !== null ? editorRootElement.getBoundingClientRect().width - 20 : 100);
39
39
  const maxHeightContainer = editorRootElement !== null ? editorRootElement.getBoundingClientRect().height - 20 : 100;
40
40
  const minWidth = 100;
41
41
  const minHeight = 100;
@@ -1,6 +1,6 @@
1
- import { $isLinkNode, $createLinkNode, TOGGLE_LINK_COMMAND, LinkNode } from "@lexical/link";
1
+ import { $isLinkNode, $createLinkNode, $isAutoLinkNode, TOGGLE_LINK_COMMAND, LinkNode } from "@lexical/link";
2
2
  import { Signal, Cell, Action, withLatestFrom, map, filter } from "@mdxeditor/gurx";
3
- import { KEY_ESCAPE_COMMAND, COMMAND_PRIORITY_LOW, KEY_MODIFIER_COMMAND, $getSelection, $isRangeSelection, COMMAND_PRIORITY_HIGH, $getNodeByKey, $createTextNode, $insertNodes, $isTextNode, $getNearestNodeFromDOMNode } from "lexical";
3
+ import { KEY_ESCAPE_COMMAND, COMMAND_PRIORITY_LOW, KEY_DOWN_COMMAND, $getSelection, $isRangeSelection, COMMAND_PRIORITY_HIGH, $getNodeByKey, $createTextNode, $insertNodes, $isTextNode, $getNearestNodeFromDOMNode } from "lexical";
4
4
  import { realmPlugin } from "../../RealmWithPlugins.js";
5
5
  import { IS_APPLE } from "../../utils/detectMac.js";
6
6
  import { getSelectionRectangle, getSelectedNode } from "../../utils/lexicalHelpers.js";
@@ -46,7 +46,7 @@ const linkDialogState$ = Cell({ type: "inactive" }, (r) => {
46
46
  });
47
47
  r.pub(createActiveEditorSubscription$, (editor) => {
48
48
  return editor.registerCommand(
49
- KEY_MODIFIER_COMMAND,
49
+ KEY_DOWN_COMMAND,
50
50
  (event) => {
51
51
  if (event.key === "k" && (IS_APPLE ? event.metaKey : event.ctrlKey) && !r.getValue(readOnly$)) {
52
52
  const selection = $getSelection();
@@ -104,9 +104,16 @@ const linkDialogState$ = Cell({ type: "inactive" }, (r) => {
104
104
  $insertNodes([node]);
105
105
  node.select();
106
106
  } else {
107
- linkNode.setURL(url);
108
- linkNode.setTitle(title);
109
- updateLinkText(linkNode.getFirstChild(), text);
107
+ if ($isAutoLinkNode(linkNode)) {
108
+ const newLinkNode = $createLinkNode(url, { title });
109
+ newLinkNode.append($createTextNode(text));
110
+ linkNode.replace(newLinkNode);
111
+ newLinkNode.select();
112
+ } else {
113
+ linkNode.setURL(url);
114
+ linkNode.setTitle(title);
115
+ updateLinkText(linkNode.getFirstChild(), text);
116
+ }
110
117
  }
111
118
  },
112
119
  { discrete: true }
@@ -23,12 +23,10 @@ const LexicalListItemVisitor = {
23
23
  let surroundingParagraph = null;
24
24
  for (const child of lexicalNode.getChildren()) {
25
25
  if ($isTextNode(child) || $isLineBreakNode(child) || child.isInline() && ($isElementNode(child) || $isDecoratorNode(child))) {
26
- if (!surroundingParagraph) {
27
- surroundingParagraph = actions.appendToParent(listItem, {
28
- type: "paragraph",
29
- children: []
30
- });
31
- }
26
+ surroundingParagraph ?? (surroundingParagraph = actions.appendToParent(listItem, {
27
+ type: "paragraph",
28
+ children: []
29
+ }));
32
30
  actions.visit(child, surroundingParagraph);
33
31
  } else {
34
32
  surroundingParagraph = null;
@@ -29,9 +29,7 @@ const currentListType$ = Cell("", (r) => {
29
29
  const parent = e.getParent();
30
30
  return parent !== null && $isRootOrShadowRoot(parent);
31
31
  });
32
- if (element === null) {
33
- element = anchorNode.getTopLevelElementOrThrow();
34
- }
32
+ element ?? (element = anchorNode.getTopLevelElementOrThrow());
35
33
  const elementKey = element.getKey();
36
34
  const elementDOM = theEditor.getElementByKey(elementKey);
37
35
  if (elementDOM !== null) {
@@ -1,4 +1,4 @@
1
- import { trimTextContentFromAnchor } from "@lexical/selection";
1
+ import { $trimTextContentFromAnchor } from "@lexical/selection";
2
2
  import { $restoreEditorState } from "@lexical/utils";
3
3
  import { RootNode, $getSelection, $isRangeSelection } from "lexical";
4
4
  import { realmPlugin } from "../../RealmWithPlugins.js";
@@ -23,7 +23,7 @@ const maxLengthPlugin = realmPlugin({
23
23
  lastRestoredEditorState = prevEditorState;
24
24
  $restoreEditorState(editor, prevEditorState);
25
25
  } else {
26
- trimTextContentFromAnchor(editor, anchor, delCount);
26
+ $trimTextContentFromAnchor(editor, anchor, delCount);
27
27
  }
28
28
  }
29
29
  }
@@ -33,9 +33,7 @@ const TableEditor = ({ mdastNode, parentEditor, lexicalTable }) => {
33
33
  const [iconComponentFor, readOnly] = useCellValues(iconComponentFor$, readOnly$);
34
34
  const getCellKey = React__default.useMemo(() => {
35
35
  return (cell) => {
36
- if (!cell.__cacheKey) {
37
- cell.__cacheKey = uuidv4();
38
- }
36
+ cell.__cacheKey ?? (cell.__cacheKey = uuidv4());
39
37
  return cell.__cacheKey;
40
38
  };
41
39
  }, []);
@@ -323,7 +321,9 @@ const CellEditor = ({ focus, setActiveCell, parentEditor, lexicalTable, contents
323
321
  );
324
322
  }, [colIndex, editor, rootEditor, rowIndex, saveAndFocus, setActiveCell]);
325
323
  React__default.useEffect(() => {
326
- focus && editor.focus();
324
+ if (focus) {
325
+ editor.focus();
326
+ }
327
327
  }, [focus, editor]);
328
328
  return /* @__PURE__ */ React__default.createElement(LexicalNestedComposer, { initialEditor: editor }, /* @__PURE__ */ React__default.createElement(RichTextPlugin, { contentEditable: /* @__PURE__ */ React__default.createElement(ContentEditable, null), placeholder: /* @__PURE__ */ React__default.createElement("div", null), ErrorBoundary: LexicalErrorBoundary }), nestedEditorChildren.map((Child, index) => /* @__PURE__ */ React__default.createElement(Child, { key: index })), /* @__PURE__ */ React__default.createElement(HistoryPlugin, null));
329
329
  };
@@ -157,9 +157,7 @@ class TableNode extends DecoratorNode {
157
157
  setColumnAlign(colIndex, align) {
158
158
  const self = this.getWritable();
159
159
  const table = self.__mdastNode;
160
- if (table.align == null) {
161
- table.align = [];
162
- }
160
+ table.align ?? (table.align = []);
163
161
  table.align[colIndex] = align;
164
162
  }
165
163
  /** @internal */
@@ -195,7 +193,7 @@ function $convertTableElement(element) {
195
193
  children: [
196
194
  {
197
195
  type: "text",
198
- value: cell.textContent ?? ""
196
+ value: cell.textContent
199
197
  }
200
198
  ]
201
199
  };
@@ -1,14 +1,18 @@
1
1
  import { useCellValues } from "@mdxeditor/gurx";
2
2
  import React__default from "react";
3
3
  import styles from "../../../styles/ui.module.css.js";
4
+ import { $isCodeBlockNode } from "../../codeblock/CodeBlockNode.js";
4
5
  import { codeBlockLanguages$ } from "../../codemirror/index.js";
5
6
  import { editorInFocus$, activeEditor$, useTranslation } from "../../core/index.js";
6
7
  import { Select } from "../primitives/select.js";
7
8
  const EMPTY_VALUE = "__EMPTY_VALUE__";
8
9
  const ChangeCodeMirrorLanguage = () => {
9
10
  const [editorInFocus, theEditor, codeBlockLanguages] = useCellValues(editorInFocus$, activeEditor$, codeBlockLanguages$);
10
- const codeBlockNode = editorInFocus.rootNode;
11
+ const codeBlockNode = $isCodeBlockNode(editorInFocus.rootNode) ? editorInFocus.rootNode : null;
11
12
  const t = useTranslation();
13
+ if (!codeBlockNode) {
14
+ return null;
15
+ }
12
16
  let currentLanguage = codeBlockNode.getLanguage();
13
17
  if (currentLanguage === "") {
14
18
  currentLanguage = EMPTY_VALUE;
@@ -1,5 +1,6 @@
1
1
  import React__default from "react";
2
2
  import styles from "../../../styles/ui.module.css.js";
3
+ import { $isCodeBlockNode } from "../../codeblock/CodeBlockNode.js";
3
4
  import { editorInFocus$, activeEditor$, iconComponentFor$, useTranslation } from "../../core/index.js";
4
5
  import { sandpackConfig$ } from "../../sandpack/index.js";
5
6
  import { ButtonWithTooltip } from "../primitives/toolbar.js";
@@ -11,8 +12,11 @@ const ShowSandpackInfo = () => {
11
12
  iconComponentFor$,
12
13
  sandpackConfig$
13
14
  );
14
- const sandpackNode = editorInFocus.rootNode;
15
15
  const t = useTranslation();
16
+ const sandpackNode = $isCodeBlockNode(editorInFocus.rootNode) ? editorInFocus.rootNode : null;
17
+ if (!sandpackNode) {
18
+ return null;
19
+ }
16
20
  const preset = sandpackConfig.presets.find((preset2) => preset2.meta === sandpackNode.getMeta());
17
21
  return /* @__PURE__ */ React__default.createElement("div", { className: styles.selectWithLabel }, /* @__PURE__ */ React__default.createElement(
18
22
  ButtonWithTooltip,
@@ -1,5 +1,9 @@
1
1
  const CAN_USE_DOM = typeof window !== "undefined" && typeof window.document.createElement !== "undefined";
2
- const IS_APPLE = CAN_USE_DOM && /Mac|iPod|iPhone|iPad/.test(navigator.platform);
2
+ const IS_APPLE = CAN_USE_DOM && (() => {
3
+ var _a;
4
+ const platform = (_a = navigator.userAgentData) == null ? void 0 : _a.platform;
5
+ return platform ? /mac/i.test(platform) : /Mac|iPod|iPhone|iPad/.test(navigator.userAgent);
6
+ })();
3
7
  function controlOrMeta(metaKey, ctrlKey) {
4
8
  if (IS_APPLE) {
5
9
  return metaKey;
@@ -27,10 +27,26 @@ function getSelectedNode(selection) {
27
27
  } else {
28
28
  return $isAtNodeEnd(anchor) ? anchorNode : focusNode;
29
29
  }
30
- } catch (e) {
30
+ } catch {
31
31
  return null;
32
32
  }
33
33
  }
34
+ const WILL_CHANGE_CONTAINING_BLOCK_PROPS = ["transform", "perspective", "filter", "backdrop-filter", "contain", "container-type"];
35
+ const CONTAIN_VALUES_CREATING_CONTAINING_BLOCK = ["layout", "paint", "strict", "content"];
36
+ function getFixedContainingBlock(element) {
37
+ let current = element == null ? void 0 : element.parentElement;
38
+ while (current) {
39
+ const style = window.getComputedStyle(current);
40
+ const willChangeProps = style.willChange.split(",").map((v) => v.trim());
41
+ const hasRelevantWillChange = willChangeProps.some((prop) => WILL_CHANGE_CONTAINING_BLOCK_PROPS.includes(prop));
42
+ const createsContainingBlock = style.transform !== "none" || style.perspective !== "none" || style.filter !== "none" || style.backdropFilter !== "none" || CONTAIN_VALUES_CREATING_CONTAINING_BLOCK.includes(style.contain) || style.containerType !== "normal" || style.contentVisibility === "auto" || hasRelevantWillChange;
43
+ if (createsContainingBlock) {
44
+ return current;
45
+ }
46
+ current = current.parentElement;
47
+ }
48
+ return null;
49
+ }
34
50
  function getSelectionRectangle(editor) {
35
51
  const selection = $getSelection();
36
52
  const nativeSelection = window.getSelection();
@@ -57,13 +73,23 @@ function getSelectionRectangle(editor) {
57
73
  rect = domRange.getBoundingClientRect();
58
74
  }
59
75
  }
76
+ const fixedContainer = getFixedContainingBlock(rootElement);
77
+ if (fixedContainer) {
78
+ const containerRect = fixedContainer.getBoundingClientRect();
79
+ return {
80
+ top: Math.round(rect.top - containerRect.top),
81
+ left: Math.round(rect.left - containerRect.left),
82
+ width: Math.round(rect.width),
83
+ height: Math.round(rect.height)
84
+ };
85
+ }
60
86
  return {
61
87
  top: Math.round(rect.top),
62
88
  left: Math.round(rect.left),
63
89
  width: Math.round(rect.width),
64
90
  height: Math.round(rect.height)
65
91
  };
66
- } else if (!activeElement || activeElement.className !== "link-input") {
92
+ } else if ((activeElement == null ? void 0 : activeElement.className) !== "link-input") {
67
93
  return null;
68
94
  }
69
95
  return null;
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "*.css"
12
12
  ],
13
13
  "type": "module",
14
- "version": "3.52.1",
14
+ "version": "3.52.3",
15
15
  "description": "React component for rich text markdown editing",
16
16
  "scripts": {
17
17
  "build": "vite build",
@@ -107,6 +107,7 @@
107
107
  "@babel/preset-typescript": "^7.23.3",
108
108
  "@ladle/react": "^5.0.2",
109
109
  "@ngneat/falso": "^6.4.0",
110
+ "@testing-library/dom": "^10.4.1",
110
111
  "@testing-library/jest-dom": "^6.1.6",
111
112
  "@testing-library/react": "^16.3.0",
112
113
  "@types/express": "^4.17.17",
@@ -117,14 +118,14 @@
117
118
  "@types/react": "^19.2.7",
118
119
  "@types/react-dom": "^19.2.3",
119
120
  "@types/unist": "^3.0.2",
120
- "@typescript-eslint/eslint-plugin": "^7.9.0",
121
- "@typescript-eslint/parser": "^7.9.0",
121
+ "@typescript-eslint/eslint-plugin": "^8.50.1",
122
+ "@typescript-eslint/parser": "^8.50.1",
122
123
  "@vitejs/plugin-react": "^4.0.0",
123
124
  "@vitejs/plugin-react-swc": "^3.5.0",
124
125
  "autoprefixer": "^10.4.14",
125
126
  "cm6-theme-basic-dark": "^0.2.0",
126
127
  "dotenv": "^16.4.5",
127
- "eslint": "^8.56.0",
128
+ "eslint": "^8.57.0",
128
129
  "eslint-config-prettier": "^9.1.0",
129
130
  "eslint-plugin-html": "^7.1.0",
130
131
  "eslint-plugin-import": "^2.29.1",
@@ -152,9 +153,9 @@
152
153
  "typedoc": "^0.25.13",
153
154
  "typedoc-plugin-markdown": "^4.0.2",
154
155
  "typedoc-plugin-no-inherit": "^1.4.0",
155
- "typescript": "^5.4.5",
156
- "typescript-eslint": "^7.9.0",
156
+ "typescript": "^5.9.3",
157
157
  "typescript-plugin-css-modules": "^5.0.2",
158
+ "user-agent-data-types": "^0.4.2",
158
159
  "vite": "^5.0.10",
159
160
  "vite-plugin-dts": "^3.9.1",
160
161
  "vite-plugin-svgr": "^4.2.0",