@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 +1 -1
- package/dist/defaultSvgIcons.js +19 -0
- package/dist/index.d.ts +21 -1
- package/dist/index.js +5 -1
- package/dist/plugins/core/LexicalTextVisitor.js +14 -2
- package/dist/plugins/core/MdastFormattingVisitor.js +10 -1
- package/dist/plugins/core/index.js +5 -3
- package/dist/plugins/image/EditImageToolbar.js +6 -3
- package/dist/plugins/image/ImageDialog.js +10 -5
- package/dist/plugins/image/ImageEditor.js +20 -3
- package/dist/plugins/image/index.js +25 -3
- package/dist/plugins/toolbar/components/HighlightToggle.js +28 -0
- package/dist/plugins/toolbar/components/KitchenSinkToolbar.js +2 -1
- package/dist/style.css +252 -247
- package/dist/styles/ui.module.css.js +97 -94
- package/package.json +3 -1
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
|
|
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
|
|
package/dist/defaultSvgIcons.js
CHANGED
|
@@ -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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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({
|
|
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) }]
|