@mdxeditor/editor 3.40.1 → 3.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -26,7 +26,7 @@ If you find a bug, check if something similar is not reported already in the [is
26
26
 
27
27
  If you're integrating the component in your commercial project and need dedicated assistance with your issues in exchange of sponsorship, [contact me over email](mailto:petyo@mdxeditor.dev).
28
28
 
29
- If you want to discuss ideas [join the Discord server](https://discord.gg/4q7U2Hc) or start a discussion in the [Discussions](https://github.com/mdx-editor/editor/discussions) section.
29
+ If you want to discuss ideas start a discussion in the [Discussions](https://github.com/mdx-editor/editor/discussions) section.
30
30
 
31
31
  ## License
32
32
 
@@ -35,6 +35,25 @@ const defaultSvgIcons = {
35
35
  fill: "currentColor"
36
36
  }
37
37
  )),
38
+ format_highlight: (
39
+ /* taken from from https://lucide.dev/icons/highlighter */
40
+ /* @__PURE__ */ React__default.createElement(
41
+ "svg",
42
+ {
43
+ xmlns: "http://www.w3.org/2000/svg",
44
+ width: "24",
45
+ height: "24",
46
+ viewBox: "0 0 24 24",
47
+ fill: "none",
48
+ stroke: "currentColor",
49
+ strokeWidth: "1.75",
50
+ strokeLinecap: "round",
51
+ strokeLinejoin: "round"
52
+ },
53
+ /* @__PURE__ */ React__default.createElement("path", { d: "m9 11-6 6v3h9l3-3" }),
54
+ /* @__PURE__ */ React__default.createElement("path", { d: "m22 12-4.6 4.6a2 2 0 0 1-2.8 0l-5.2-5.2a2 2 0 0 1 0-2.8L14 4" })
55
+ )
56
+ ),
38
57
  code: /* @__PURE__ */ React__default.createElement("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ React__default.createElement(
39
58
  "path",
40
59
  {
package/dist/index.d.ts CHANGED
@@ -268,6 +268,12 @@ export declare const ALL_HEADING_LEVELS: readonly [1, 2, 3, 4, 5, 6];
268
268
  */
269
269
  export declare const allowedHeadingLevels$: NodeRef<readonly HEADING_LEVEL[]>;
270
270
 
271
+ /**
272
+ * Allow to set width and height of image through dialog window
273
+ * @group Image
274
+ */
275
+ export declare const allowSetImageDimensions$: NodeRef<boolean>;
276
+
271
277
  /**
272
278
  * returns a function which when called always returns the passed value
273
279
  * @group Utils
@@ -311,6 +317,8 @@ export declare const applyListType$: NodeRef<"" | ListType>;
311
317
  declare interface BaseImageParameters {
312
318
  altText?: string;
313
319
  title?: string;
320
+ width?: number;
321
+ height?: number;
314
322
  }
315
323
 
316
324
  /**
@@ -814,6 +822,7 @@ export declare const defaultSvgIcons: {
814
822
  format_bold: default_2.JSX.Element;
815
823
  format_italic: default_2.JSX.Element;
816
824
  format_underlined: default_2.JSX.Element;
825
+ format_highlight: default_2.JSX.Element;
817
826
  code: default_2.JSX.Element;
818
827
  strikeThrough: default_2.JSX.Element;
819
828
  superscript: default_2.JSX.Element;
@@ -1086,6 +1095,8 @@ declare interface EditImageToolbarProps {
1086
1095
  initialImagePath: string | null;
1087
1096
  title: string;
1088
1097
  alt: string;
1098
+ width?: number | 'inherit';
1099
+ height?: number | 'inherit';
1089
1100
  }
1090
1101
 
1091
1102
  /**
@@ -1332,6 +1343,12 @@ export declare const headingsPlugin: (params?: {
1332
1343
  allowedHeadingLevels?: readonly HEADING_LEVEL[] | undefined;
1333
1344
  } | undefined) => RealmPlugin;
1334
1345
 
1346
+ /**
1347
+ * A toolbar component that lets the user toggle highlight formatting.
1348
+ * @group Toolbar Components
1349
+ */
1350
+ export declare const HighlightToggle: default_2.FC;
1351
+
1335
1352
  /* Excluded from this release type: historyState$ */
1336
1353
 
1337
1354
  /**
@@ -1346,7 +1363,7 @@ export declare const htmlTags: string[];
1346
1363
  */
1347
1364
  export declare const iconComponentFor$: NodeRef<(name: IconKey) => default_2.ReactNode>;
1348
1365
 
1349
- export declare type IconKey = 'undo' | 'redo' | 'format_bold' | 'format_italic' | 'format_underlined' | 'code' | 'strikeThrough' | 'superscript' | 'subscript' | 'format_list_bulleted' | 'format_list_numbered' | 'format_list_checked' | 'link' | 'add_photo' | 'table' | 'horizontal_rule' | 'frontmatter' | 'frame_source' | 'arrow_drop_down' | 'admonition' | 'sandpack' | 'rich_text' | 'difference' | 'markdown' | 'open_in_new' | 'link_off' | 'edit' | 'content_copy' | 'more_horiz' | 'more_vert' | 'close' | 'settings' | 'delete_big' | 'delete_small' | 'format_align_center' | 'format_align_left' | 'format_align_right' | 'add_row' | 'add_column' | 'insert_col_left' | 'insert_row_above' | 'insert_row_below' | 'insert_col_right' | 'check';
1366
+ export declare type IconKey = 'undo' | 'redo' | 'format_bold' | 'format_italic' | 'format_underlined' | 'code' | 'strikeThrough' | 'superscript' | 'subscript' | 'format_list_bulleted' | 'format_list_numbered' | 'format_list_checked' | 'format_highlight' | 'link' | 'add_photo' | 'table' | 'horizontal_rule' | 'frontmatter' | 'frame_source' | 'arrow_drop_down' | 'admonition' | 'sandpack' | 'rich_text' | 'difference' | 'markdown' | 'open_in_new' | 'link_off' | 'edit' | 'content_copy' | 'more_horiz' | 'more_vert' | 'close' | 'settings' | 'delete_big' | 'delete_small' | 'format_align_center' | 'format_align_left' | 'format_align_right' | 'add_row' | 'add_column' | 'insert_col_left' | 'insert_row_above' | 'insert_row_below' | 'insert_col_right' | 'check';
1350
1367
 
1351
1368
  /**
1352
1369
  * Holds the autocomplete suggestions for image sources.
@@ -1416,6 +1433,7 @@ export declare const imagePlugin: (params?: {
1416
1433
  imageAutocompleteSuggestions?: string[] | undefined;
1417
1434
  disableImageResize?: boolean | undefined;
1418
1435
  disableImageSettingsButton?: boolean | undefined;
1436
+ allowSetImageDimensions?: boolean | undefined;
1419
1437
  imagePreviewHandler?: ImagePreviewHandler | undefined;
1420
1438
  ImageDialog?: FC<{}> | (() => JSX.Element) | undefined;
1421
1439
  EditImageToolbar?: FC<{}> | (() => JSX.Element) | undefined;
@@ -2441,6 +2459,8 @@ export declare const openLinkEditDialog$: NodeRef<void>;
2441
2459
  */
2442
2460
  export declare const openNewImageDialog$: NodeRef<void>;
2443
2461
 
2462
+ export declare const parseImageDimension: (value: string | number | undefined) => number | undefined;
2463
+
2444
2464
  /* Excluded from this release type: placeholder$ */
2445
2465
 
2446
2466
  /**
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import { insertThematicBreak$, thematicBreakPlugin } from "./plugins/thematic-br
10
10
  import { applyListType$, currentListType$, listsPlugin } from "./plugins/lists/index.js";
11
11
  import { insertTable$, tablePlugin } from "./plugins/table/index.js";
12
12
  import { disableAutoLink$, linkPlugin } from "./plugins/link/index.js";
13
- import { INSERT_IMAGE_COMMAND, closeImageDialog$, disableImageResize$, disableImageSettingsButton$, editImageToolbarComponent$, imageAutocompleteSuggestions$, imageDialogState$, imagePlaceholder$, imagePlugin, imagePreviewHandler$, imageUploadHandler$, insertImage$, openEditImageDialog$, openNewImageDialog$, saveImage$ } from "./plugins/image/index.js";
13
+ import { INSERT_IMAGE_COMMAND, allowSetImageDimensions$, closeImageDialog$, disableImageResize$, disableImageSettingsButton$, editImageToolbarComponent$, imageAutocompleteSuggestions$, imageDialogState$, imagePlaceholder$, imagePlugin, imagePreviewHandler$, imageUploadHandler$, insertImage$, openEditImageDialog$, openNewImageDialog$, parseImageDimension, saveImage$ } from "./plugins/image/index.js";
14
14
  import { frontmatterDialogOpen$, frontmatterPlugin, hasFrontmatter$, insertFrontmatter$, removeFrontmatter$ } from "./plugins/frontmatter/index.js";
15
15
  import { quotePlugin } from "./plugins/quote/index.js";
16
16
  import { maxLengthPlugin } from "./plugins/maxlength/index.js";
@@ -34,6 +34,7 @@ import { BoldItalicUnderlineToggles, StrikeThroughSupSubToggles } from "./plugin
34
34
  import { ChangeAdmonitionType, admonitionLabelsMap } from "./plugins/toolbar/components/ChangeAdmonitionType.js";
35
35
  import { ChangeCodeMirrorLanguage } from "./plugins/toolbar/components/ChangeCodeMirrorLanguage.js";
36
36
  import { CodeToggle } from "./plugins/toolbar/components/CodeToggle.js";
37
+ import { HighlightToggle } from "./plugins/toolbar/components/HighlightToggle.js";
37
38
  import { CreateLink } from "./plugins/toolbar/components/CreateLink.js";
38
39
  import { DiffSourceToggleWrapper } from "./plugins/toolbar/components/DiffSourceToggleWrapper.js";
39
40
  import { InsertAdmonition } from "./plugins/toolbar/components/InsertAdmonition.js";
@@ -114,6 +115,7 @@ export {
114
115
  GenericDirectiveEditor,
115
116
  GenericHTMLNode,
116
117
  GenericJsxEditor,
118
+ HighlightToggle,
117
119
  INSERT_IMAGE_COMMAND,
118
120
  IS_APPLE,
119
121
  IS_BOLD,
@@ -180,6 +182,7 @@ export {
180
182
  addToMarkdownExtension$,
181
183
  addTopAreaChild$,
182
184
  admonitionLabelsMap,
185
+ allowSetImageDimensions$,
183
186
  allowedHeadingLevels$,
184
187
  always,
185
188
  appendCodeBlockEditorDescriptor$,
@@ -304,6 +307,7 @@ export {
304
307
  openEditImageDialog$,
305
308
  openLinkEditDialog$,
306
309
  openNewImageDialog$,
310
+ parseImageDimension,
307
311
  placeholder$,
308
312
  prop,
309
313
  quotePlugin,
@@ -1,12 +1,12 @@
1
1
  import { $isTextNode } from "lexical";
2
- import { IS_UNDERLINE, IS_SUPERSCRIPT, IS_SUBSCRIPT, IS_ITALIC, IS_BOLD, IS_STRIKETHROUGH, IS_CODE } from "../../FormatConstants.js";
2
+ import { IS_UNDERLINE, IS_SUPERSCRIPT, IS_SUBSCRIPT, IS_ITALIC, IS_BOLD, IS_STRIKETHROUGH, IS_HIGHLIGHT, IS_CODE } from "../../FormatConstants.js";
3
3
  function isMdastText(mdastNode) {
4
4
  return mdastNode.type === "text";
5
5
  }
6
6
  const JOINABLE_TAGS = ["u", "span", "sub", "sup"];
7
7
  const LexicalTextVisitor = {
8
8
  shouldJoin: (prevNode, currentNode) => {
9
- if (["text", "emphasis", "strong"].includes(prevNode.type)) {
9
+ if (["text", "emphasis", "strong", "highlight"].includes(prevNode.type)) {
10
10
  return prevNode.type === currentNode.type;
11
11
  }
12
12
  if (prevNode.type === "mdxJsxTextElement" && // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
@@ -87,6 +87,12 @@ const LexicalTextVisitor = {
87
87
  children: []
88
88
  });
89
89
  }
90
+ if (prevFormat & format & IS_HIGHLIGHT) {
91
+ localParentNode = actions.appendToParent(localParentNode, {
92
+ type: "highlight",
93
+ children: []
94
+ });
95
+ }
90
96
  if (format & IS_UNDERLINE && !(prevFormat & IS_UNDERLINE)) {
91
97
  localParentNode = actions.appendToParent(localParentNode, {
92
98
  type: "mdxJsxTextElement",
@@ -129,6 +135,12 @@ const LexicalTextVisitor = {
129
135
  children: []
130
136
  });
131
137
  }
138
+ if (format & IS_HIGHLIGHT && !(prevFormat & IS_HIGHLIGHT)) {
139
+ localParentNode = actions.appendToParent(localParentNode, {
140
+ type: "highlight",
141
+ children: []
142
+ });
143
+ }
132
144
  if (format & IS_CODE) {
133
145
  actions.appendToParent(localParentNode, {
134
146
  type: "inlineCode",
@@ -1,4 +1,4 @@
1
- import { IS_ITALIC, IS_BOLD, IS_CODE, IS_STRIKETHROUGH, IS_UNDERLINE, IS_SUPERSCRIPT, IS_SUBSCRIPT } from "../../FormatConstants.js";
1
+ import { IS_ITALIC, IS_BOLD, IS_CODE, IS_STRIKETHROUGH, IS_HIGHLIGHT, IS_UNDERLINE, IS_SUPERSCRIPT, IS_SUBSCRIPT } from "../../FormatConstants.js";
2
2
  import { $createTextNode } from "lexical";
3
3
  function buildFormattingVisitors(tag, format) {
4
4
  return [
@@ -30,6 +30,13 @@ const StrikeThroughVisitor = {
30
30
  actions.visitChildren(mdastNode, lexicalParent);
31
31
  }
32
32
  };
33
+ const HighlightVisitor = {
34
+ testNode: "highlight",
35
+ visitNode({ mdastNode, actions, lexicalParent }) {
36
+ actions.addFormatting(IS_HIGHLIGHT);
37
+ actions.visitChildren(mdastNode, lexicalParent);
38
+ }
39
+ };
33
40
  const MdCodeVisitor = {
34
41
  testNode: "inlineCode",
35
42
  visitNode({ mdastNode, actions }) {
@@ -62,6 +69,8 @@ const formattingVisitors = [
62
69
  MdCodeVisitor,
63
70
  // strikethrough
64
71
  StrikeThroughVisitor,
72
+ // highlight
73
+ HighlightVisitor,
65
74
  // superscript
66
75
  ...buildFormattingVisitors("sup", IS_SUPERSCRIPT),
67
76
  // subscript
@@ -7,7 +7,9 @@ import { Cell, Signal, withLatestFrom, filter, useCellValue, scan, map } from "@
7
7
  import { createCommand, FORMAT_TEXT_COMMAND, $isRootOrShadowRoot, $getRoot, $setSelection, $getSelection, $insertNodes, SELECTION_CHANGE_COMMAND, COMMAND_PRIORITY_CRITICAL, DecoratorNode, $createParagraphNode, FOCUS_COMMAND, BLUR_COMMAND, $isRangeSelection, createEditor, ParagraphNode, TextNode } from "lexical";
8
8
  import { gfmStrikethrough } from "micromark-extension-gfm-strikethrough";
9
9
  import { gfmStrikethroughToMarkdown, gfmStrikethroughFromMarkdown } from "mdast-util-gfm-strikethrough";
10
+ import { highlightMarkToMarkdown, highlightMarkFromMarkdown } from "mdast-util-highlight-mark";
10
11
  import { mdxJsxToMarkdown, mdxJsxFromMarkdown } from "mdast-util-mdx-jsx";
12
+ import { highlightMark } from "micromark-extension-highlight-mark";
11
13
  import { mdxJsx } from "micromark-extension-mdx-jsx";
12
14
  import { mdxMd } from "micromark-extension-mdx-md";
13
15
  import { exportMarkdownFromLexical } from "../../exportMarkdownFromLexical.js";
@@ -516,9 +518,9 @@ const corePlugin = realmPlugin({
516
518
  [placeholder$]: params == null ? void 0 : params.placeholder,
517
519
  [readOnly$]: params == null ? void 0 : params.readOnly,
518
520
  [translation$]: params == null ? void 0 : params.translation,
519
- [addMdastExtension$]: gfmStrikethroughFromMarkdown(),
520
- [addSyntaxExtension$]: gfmStrikethrough(),
521
- [addToMarkdownExtension$]: [mdxJsxToMarkdown(), gfmStrikethroughToMarkdown()],
521
+ [addMdastExtension$]: [gfmStrikethroughFromMarkdown(), highlightMarkFromMarkdown],
522
+ [addSyntaxExtension$]: [gfmStrikethrough(), highlightMark()],
523
+ [addToMarkdownExtension$]: [mdxJsxToMarkdown(), gfmStrikethroughToMarkdown(), highlightMarkToMarkdown],
522
524
  [lexicalTheme$]: (params == null ? void 0 : params.lexicalTheme) ?? lexicalTheme
523
525
  });
524
526
  r.singletonSub(markdownErrorSignal$, params == null ? void 0 : params.onError);
@@ -3,10 +3,11 @@ import { useCellValues, usePublisher } from "@mdxeditor/gurx";
3
3
  import classNames from "classnames";
4
4
  import { $getNodeByKey } from "lexical";
5
5
  import React__default from "react";
6
- import { disableImageSettingsButton$, openEditImageDialog$ } from "./index.js";
6
+ import { disableImageSettingsButton$, openEditImageDialog$, parseImageDimension } from "./index.js";
7
7
  import styles from "../../styles/ui.module.css.js";
8
8
  import { iconComponentFor$, readOnly$, useTranslation } from "../core/index.js";
9
- function EditImageToolbar({ nodeKey, imageSource, initialImagePath, title, alt }) {
9
+ function EditImageToolbar(props) {
10
+ const { nodeKey, imageSource, initialImagePath, title, alt, width, height } = props;
10
11
  const [disableImageSettingsButton, iconComponentFor, readOnly] = useCellValues(disableImageSettingsButton$, iconComponentFor$, readOnly$);
11
12
  const [editor] = useLexicalComposerContext();
12
13
  const openEditImageDialog = usePublisher(openEditImageDialog$);
@@ -40,7 +41,9 @@ function EditImageToolbar({ nodeKey, imageSource, initialImagePath, title, alt }
40
41
  initialValues: {
41
42
  src: !initialImagePath ? imageSource : initialImagePath,
42
43
  title,
43
- altText: alt
44
+ altText: alt,
45
+ width: parseImageDimension(width),
46
+ height: parseImageDimension(height)
44
47
  }
45
48
  });
46
49
  }
@@ -4,15 +4,16 @@ import React__default from "react";
4
4
  import { useForm } from "react-hook-form";
5
5
  import styles from "../../styles/ui.module.css.js";
6
6
  import { editorRootElementRef$, useTranslation } from "../core/index.js";
7
- import { imageAutocompleteSuggestions$, imageDialogState$, imageUploadHandler$, saveImage$, closeImageDialog$ } from "./index.js";
7
+ import { imageAutocompleteSuggestions$, imageDialogState$, imageUploadHandler$, allowSetImageDimensions$, saveImage$, closeImageDialog$ } from "./index.js";
8
8
  import { DownshiftAutoComplete } from "../core/ui/DownshiftAutoComplete.js";
9
9
  import { useCellValues, usePublisher } from "@mdxeditor/gurx";
10
10
  const ImageDialog = () => {
11
- const [imageAutocompleteSuggestions, state, editorRootElementRef, imageUploadHandler] = useCellValues(
11
+ const [imageAutocompleteSuggestions, state, editorRootElementRef, imageUploadHandler, allowSetImageDimensions] = useCellValues(
12
12
  imageAutocompleteSuggestions$,
13
13
  imageDialogState$,
14
14
  editorRootElementRef$,
15
- imageUploadHandler$
15
+ imageUploadHandler$,
16
+ allowSetImageDimensions$
16
17
  );
17
18
  const saveImage = usePublisher(saveImage$);
18
19
  const closeImageDialog = usePublisher(closeImageDialog$);
@@ -21,6 +22,9 @@ const ImageDialog = () => {
21
22
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
22
23
  values: state.type === "editing" ? state.initialValues : {}
23
24
  });
25
+ const resetFormState = () => {
26
+ reset({ src: "", title: "", altText: "", width: void 0, height: void 0 });
27
+ };
24
28
  if (state.type === "inactive")
25
29
  return null;
26
30
  return /* @__PURE__ */ React__default.createElement(
@@ -30,7 +34,7 @@ const ImageDialog = () => {
30
34
  onOpenChange: (open) => {
31
35
  if (!open) {
32
36
  closeImageDialog();
33
- reset({ src: "", title: "", altText: "" });
37
+ resetFormState();
34
38
  }
35
39
  }
36
40
  },
@@ -50,7 +54,7 @@ const ImageDialog = () => {
50
54
  e.preventDefault();
51
55
  e.stopPropagation();
52
56
  await handleSubmit(saveImage)(e);
53
- reset({ src: "", title: "", altText: "" });
57
+ resetFormState();
54
58
  },
55
59
  className: styles.multiFieldForm
56
60
  },
@@ -69,6 +73,7 @@ const ImageDialog = () => {
69
73
  )),
70
74
  /* @__PURE__ */ React__default.createElement("div", { className: styles.formField }, /* @__PURE__ */ React__default.createElement("label", { htmlFor: "alt" }, t("uploadImage.alt", "Alt:")), /* @__PURE__ */ React__default.createElement("input", { type: "text", ...register("altText"), className: styles.textInput })),
71
75
  /* @__PURE__ */ React__default.createElement("div", { className: styles.formField }, /* @__PURE__ */ React__default.createElement("label", { htmlFor: "title" }, t("uploadImage.title", "Title:")), /* @__PURE__ */ React__default.createElement("input", { type: "text", ...register("title"), className: styles.textInput })),
76
+ allowSetImageDimensions && /* @__PURE__ */ React__default.createElement("div", { className: styles.imageDimensionsContainer }, /* @__PURE__ */ React__default.createElement("div", { className: styles.formField }, /* @__PURE__ */ React__default.createElement("label", { htmlFor: "width" }, t("uploadImage.width", "Width:")), /* @__PURE__ */ React__default.createElement("input", { type: "number", min: 0, ...register("width"), className: styles.textInput })), /* @__PURE__ */ React__default.createElement("div", { className: styles.formField }, /* @__PURE__ */ React__default.createElement("label", { htmlFor: "height" }, t("uploadImage.height", "Height:")), /* @__PURE__ */ React__default.createElement("input", { type: "number", min: 0, ...register("height"), className: styles.textInput }))),
72
77
  /* @__PURE__ */ React__default.createElement("div", { style: { display: "flex", justifyContent: "flex-end", gap: "var(--spacing-2)" } }, /* @__PURE__ */ React__default.createElement(
73
78
  "button",
74
79
  {
@@ -5,7 +5,7 @@ import { mergeRegister } from "@lexical/utils";
5
5
  import { useCellValues } from "@mdxeditor/gurx";
6
6
  import classNames from "classnames";
7
7
  import { $isNodeSelection, $getSelection, $getNodeByKey, $setSelection, SELECTION_CHANGE_COMMAND, COMMAND_PRIORITY_LOW, CLICK_COMMAND, DRAGSTART_COMMAND, KEY_DELETE_COMMAND, KEY_BACKSPACE_COMMAND, KEY_ENTER_COMMAND, KEY_ESCAPE_COMMAND } from "lexical";
8
- import { imagePlaceholder$, disableImageResize$, imagePreviewHandler$, editImageToolbarComponent$ } from "./index.js";
8
+ import { imagePlaceholder$, disableImageResize$, allowSetImageDimensions$, imagePreviewHandler$, editImageToolbarComponent$ } from "./index.js";
9
9
  import styles from "../../styles/ui.module.css.js";
10
10
  import { readOnly$ } from "../core/index.js";
11
11
  import { $isImageNode } from "./ImageNode.js";
@@ -66,9 +66,10 @@ function LazyImage({
66
66
  );
67
67
  }
68
68
  function ImageEditor({ src, title, alt, nodeKey, width, height, rest }) {
69
- const [ImagePlaceholderComponent, disableImageResize, imagePreviewHandler, readOnly, EditImageToolbar] = useCellValues(
69
+ const [ImagePlaceholderComponent, disableImageResize, allowSetImageDimensions, imagePreviewHandler, readOnly, EditImageToolbar] = useCellValues(
70
70
  imagePlaceholder$,
71
71
  disableImageResize$,
72
+ allowSetImageDimensions$,
72
73
  imagePreviewHandler$,
73
74
  readOnly$,
74
75
  editImageToolbarComponent$
@@ -143,6 +144,13 @@ function ImageEditor({ src, title, alt, nodeKey, width, height, rest }) {
143
144
  setImageSource(src);
144
145
  }
145
146
  }, [src, imagePreviewHandler, initialImagePath]);
147
+ React__default.useEffect(() => {
148
+ if (allowSetImageDimensions && imageRef.current) {
149
+ const { current: image } = imageRef;
150
+ syncDimensionWithImageResizer(image, "width", width);
151
+ syncDimensionWithImageResizer(image, "height", height);
152
+ }
153
+ }, [allowSetImageDimensions, width, height]);
146
154
  React__default.useEffect(() => {
147
155
  let isMounted = true;
148
156
  const unregister = mergeRegister(
@@ -249,10 +257,19 @@ function ImageEditor({ src, title, alt, nodeKey, width, height, rest }) {
249
257
  imageSource,
250
258
  initialImagePath,
251
259
  title: title ?? "",
252
- alt: alt ?? ""
260
+ alt: alt ?? "",
261
+ width,
262
+ height
253
263
  }
254
264
  ))) : null;
255
265
  }
266
+ const syncDimensionWithImageResizer = (image, key, value) => {
267
+ if (typeof value === "number") {
268
+ image.style[key] = `${value}px`;
269
+ } else {
270
+ image.style.removeProperty(key);
271
+ }
272
+ };
256
273
  export {
257
274
  ImageEditor
258
275
  };
@@ -13,7 +13,13 @@ import { MdastImageVisitor, MdastHtmlImageVisitor, MdastJsxImageVisitor } from "
13
13
  const internalInsertImage$ = Signal((r) => {
14
14
  r.sub(r.pipe(internalInsertImage$, withLatestFrom(activeEditor$)), ([values, theEditor]) => {
15
15
  theEditor == null ? void 0 : theEditor.update(() => {
16
- const imageNode = $createImageNode({ altText: values.altText ?? "", src: values.src, title: values.title ?? "" });
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
+ });
17
23
  $insertNodes([imageNode]);
18
24
  if ($isRootOrShadowRoot(imageNode.getParentOrThrow())) {
19
25
  $wrapNodeInElement(imageNode, $createParagraphNode).selectEnd();
@@ -44,8 +50,8 @@ const imageDialogState$ = Cell(
44
50
  { type: "inactive" },
45
51
  (r) => {
46
52
  r.sub(
47
- r.pipe(saveImage$, withLatestFrom(activeEditor$, imageUploadHandler$, imageDialogState$)),
48
- ([values, theEditor, imageUploadHandler, dialogState]) => {
53
+ r.pipe(saveImage$, withLatestFrom(activeEditor$, imageUploadHandler$, imageDialogState$, allowSetImageDimensions$)),
54
+ ([values, theEditor, imageUploadHandler, dialogState, allowSetImageDimensions]) => {
49
55
  const handler = dialogState.type === "editing" ? (src) => {
50
56
  theEditor == null ? void 0 : theEditor.update(() => {
51
57
  const { nodeKey } = dialogState;
@@ -53,6 +59,11 @@ const imageDialogState$ = Cell(
53
59
  imageNode.setTitle(values.title);
54
60
  imageNode.setAltText(values.altText);
55
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
+ }
56
67
  });
57
68
  r.pub(imageDialogState$, { type: "inactive" });
58
69
  } : (src) => {
@@ -158,8 +169,15 @@ const closeImageDialog$ = Action((r) => {
158
169
  r.link(r.pipe(closeImageDialog$, mapTo({ type: "inactive" })), imageDialogState$);
159
170
  });
160
171
  const disableImageSettingsButton$ = Cell(false);
172
+ const allowSetImageDimensions$ = Cell(false);
161
173
  const saveImage$ = Signal();
162
174
  const editImageToolbarComponent$ = Cell(EditImageToolbar);
175
+ const parseImageDimension = (value) => {
176
+ if (typeof value === "undefined")
177
+ return void 0;
178
+ const parsed = parseInt(String(value), 10);
179
+ return Number.isNaN(parsed) ? void 0 : parsed;
180
+ };
163
181
  const imagePlugin = realmPlugin({
164
182
  init(realm, params) {
165
183
  realm.pubIn({
@@ -171,6 +189,7 @@ const imagePlugin = realmPlugin({
171
189
  [imageAutocompleteSuggestions$]: (params == null ? void 0 : params.imageAutocompleteSuggestions) ?? [],
172
190
  [disableImageResize$]: Boolean(params == null ? void 0 : params.disableImageResize),
173
191
  [disableImageSettingsButton$]: Boolean(params == null ? void 0 : params.disableImageSettingsButton),
192
+ [allowSetImageDimensions$]: Boolean(params == null ? void 0 : params.allowSetImageDimensions),
174
193
  [imagePreviewHandler$]: (params == null ? void 0 : params.imagePreviewHandler) ?? null,
175
194
  [editImageToolbarComponent$]: (params == null ? void 0 : params.EditImageToolbar) ?? EditImageToolbar,
176
195
  [imagePlaceholder$]: (params == null ? void 0 : params.imagePlaceholder) ?? ImagePlaceholder
@@ -182,6 +201,7 @@ const imagePlugin = realmPlugin({
182
201
  [imageAutocompleteSuggestions$]: (params == null ? void 0 : params.imageAutocompleteSuggestions) ?? [],
183
202
  [disableImageResize$]: Boolean(params == null ? void 0 : params.disableImageResize),
184
203
  [imagePreviewHandler$]: (params == null ? void 0 : params.imagePreviewHandler) ?? null,
204
+ [allowSetImageDimensions$]: Boolean(params == null ? void 0 : params.allowSetImageDimensions),
185
205
  [editImageToolbarComponent$]: (params == null ? void 0 : params.EditImageToolbar) ?? EditImageToolbar,
186
206
  [imagePlaceholder$]: (params == null ? void 0 : params.imagePlaceholder) ?? ImagePlaceholder
187
207
  });
@@ -331,6 +351,7 @@ export {
331
351
  $isImageNode,
332
352
  INSERT_IMAGE_COMMAND,
333
353
  ImageNode,
354
+ allowSetImageDimensions$,
334
355
  closeImageDialog$,
335
356
  disableImageResize$,
336
357
  disableImageSettingsButton$,
@@ -344,5 +365,6 @@ export {
344
365
  insertImage$,
345
366
  openEditImageDialog$,
346
367
  openNewImageDialog$,
368
+ parseImageDimension,
347
369
  saveImage$
348
370
  };
@@ -0,0 +1,28 @@
1
+ import React__default from "react";
2
+ import { IS_HIGHLIGHT } from "../../../FormatConstants.js";
3
+ import { currentFormat$, iconComponentFor$, applyFormat$, useTranslation } from "../../core/index.js";
4
+ import { MultipleChoiceToggleGroup } from "../primitives/toolbar.js";
5
+ import { useCellValues, usePublisher } from "@mdxeditor/gurx";
6
+ const HighlightToggle = () => {
7
+ const [currentFormat, iconComponentFor] = useCellValues(currentFormat$, iconComponentFor$);
8
+ const applyFormat = usePublisher(applyFormat$);
9
+ const t = useTranslation();
10
+ const highlightIsOn = (currentFormat & IS_HIGHLIGHT) !== 0;
11
+ const title = highlightIsOn ? t("toolbar.removeHighlight", "Remove highlight") : t("toolbar.highlight", "Highlight");
12
+ return /* @__PURE__ */ React__default.createElement(
13
+ MultipleChoiceToggleGroup,
14
+ {
15
+ items: [
16
+ {
17
+ title,
18
+ contents: iconComponentFor("format_highlight"),
19
+ active: highlightIsOn,
20
+ onChange: applyFormat.bind(null, "highlight")
21
+ }
22
+ ]
23
+ }
24
+ );
25
+ };
26
+ export {
27
+ HighlightToggle
28
+ };
@@ -17,6 +17,7 @@ import { ListsToggle } from "./ListsToggle.js";
17
17
  import { ShowSandpackInfo } from "./ShowSandpackInfo.js";
18
18
  import { UndoRedo } from "./UndoRedo.js";
19
19
  import { CreateLink } from "./CreateLink.js";
20
+ import { HighlightToggle } from "./HighlightToggle.js";
20
21
  function whenInAdmonition(editorInFocus) {
21
22
  const node = editorInFocus == null ? void 0 : editorInFocus.rootNode;
22
23
  if (!node || node.getType() !== "directive") {
@@ -32,7 +33,7 @@ const KitchenSinkToolbar = () => {
32
33
  { when: (editor) => (editor == null ? void 0 : editor.editorType) === "codeblock", contents: () => /* @__PURE__ */ React__default.createElement(ChangeCodeMirrorLanguage, null) },
33
34
  { when: (editor) => (editor == null ? void 0 : editor.editorType) === "sandpack", contents: () => /* @__PURE__ */ React__default.createElement(ShowSandpackInfo, null) },
34
35
  {
35
- fallback: () => /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(UndoRedo, null), /* @__PURE__ */ React__default.createElement(Separator, null), /* @__PURE__ */ React__default.createElement(BoldItalicUnderlineToggles, null), /* @__PURE__ */ React__default.createElement(CodeToggle, null), /* @__PURE__ */ React__default.createElement(Separator, null), /* @__PURE__ */ React__default.createElement(StrikeThroughSupSubToggles, null), /* @__PURE__ */ React__default.createElement(Separator, null), /* @__PURE__ */ React__default.createElement(ListsToggle, null), /* @__PURE__ */ React__default.createElement(Separator, null), /* @__PURE__ */ React__default.createElement(
36
+ fallback: () => /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(UndoRedo, null), /* @__PURE__ */ React__default.createElement(Separator, null), /* @__PURE__ */ React__default.createElement(BoldItalicUnderlineToggles, null), /* @__PURE__ */ React__default.createElement(CodeToggle, null), /* @__PURE__ */ React__default.createElement(HighlightToggle, null), /* @__PURE__ */ React__default.createElement(Separator, null), /* @__PURE__ */ React__default.createElement(StrikeThroughSupSubToggles, null), /* @__PURE__ */ React__default.createElement(Separator, null), /* @__PURE__ */ React__default.createElement(ListsToggle, null), /* @__PURE__ */ React__default.createElement(Separator, null), /* @__PURE__ */ React__default.createElement(
36
37
  ConditionalContents,
37
38
  {
38
39
  options: [{ when: whenInAdmonition, contents: () => /* @__PURE__ */ React__default.createElement(ChangeAdmonitionType, null) }, { fallback: () => /* @__PURE__ */ React__default.createElement(BlockTypeSelect, null) }]