@mdxeditor/editor 1.1.1 → 1.2.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/dist/directive-editors/AdmonitionDirectiveDescriptor.js +1 -3
- package/dist/plugins/core/PropertyPopover.js +4 -3
- package/dist/plugins/core/ui/DownshiftAutoComplete.d.ts +11 -0
- package/dist/plugins/core/ui/DownshiftAutoComplete.js +66 -0
- package/dist/plugins/diff-source/DiffViewer.js +0 -1
- package/dist/plugins/frontmatter/FrontmatterEditor.js +23 -12
- package/dist/plugins/image/ImageDialog.d.ts +2 -0
- package/dist/plugins/image/ImageDialog.js +68 -0
- package/dist/plugins/image/ImageEditor.d.ts +2 -1
- package/dist/plugins/image/ImageEditor.js +38 -5
- package/dist/plugins/image/ImageNode.d.ts +2 -0
- package/dist/plugins/image/ImageNode.js +18 -2
- package/dist/plugins/image/index.d.ts +67 -10
- package/dist/plugins/image/index.js +56 -10
- package/dist/plugins/link-dialog/LinkDialog.d.ts +7 -4
- package/dist/plugins/link-dialog/LinkDialog.js +40 -72
- package/dist/plugins/link-dialog/index.d.ts +30 -9
- package/dist/plugins/link-dialog/index.js +24 -46
- package/dist/plugins/toolbar/components/InsertImage.js +7 -15
- package/dist/plugins/toolbar/primitives/DialogButton.js +2 -2
- package/dist/style.css +312 -217
- package/dist/styles/ui.module.css.js +119 -95
- package/package.json +4 -5
|
@@ -10,14 +10,12 @@ const AdmonitionDirectiveDescriptor = {
|
|
|
10
10
|
},
|
|
11
11
|
Editor({ mdastNode }) {
|
|
12
12
|
const {
|
|
13
|
-
config: { theme }
|
|
14
|
-
focusEmitter
|
|
13
|
+
config: { theme }
|
|
15
14
|
} = useNestedEditorContext();
|
|
16
15
|
return /* @__PURE__ */ React__default.createElement("div", { className: theme.admonition[mdastNode.name] }, /* @__PURE__ */ React__default.createElement(
|
|
17
16
|
NestedLexicalEditor,
|
|
18
17
|
{
|
|
19
18
|
block: true,
|
|
20
|
-
focusEmitter,
|
|
21
19
|
getContent: (node) => node.children,
|
|
22
20
|
getUpdatedMdastNode: (mdastNode2, children) => ({ ...mdastNode2, children })
|
|
23
21
|
}
|
|
@@ -10,10 +10,11 @@ const PropertyPopover = ({ title, properties, onChange }) => {
|
|
|
10
10
|
return /* @__PURE__ */ React__default.createElement(RadixPopover.Root, { open, onOpenChange: (v) => setOpen(v) }, /* @__PURE__ */ React__default.createElement(RadixPopover.Trigger, { className: styles.iconButton }, /* @__PURE__ */ React__default.createElement(SettingsIcon, { style: { display: "block" } })), /* @__PURE__ */ React__default.createElement(PopoverPortal, null, /* @__PURE__ */ React__default.createElement(PopoverContent, null, /* @__PURE__ */ React__default.createElement(
|
|
11
11
|
"form",
|
|
12
12
|
{
|
|
13
|
-
onSubmit:
|
|
14
|
-
onChange(
|
|
13
|
+
onSubmit: (e) => {
|
|
14
|
+
void handleSubmit(onChange)(e);
|
|
15
15
|
setOpen(false);
|
|
16
|
-
|
|
16
|
+
e.nativeEvent.stopImmediatePropagation();
|
|
17
|
+
}
|
|
17
18
|
},
|
|
18
19
|
/* @__PURE__ */ React__default.createElement("h3", { className: styles.propertyPanelTitle }, title, " Attributes"),
|
|
19
20
|
/* @__PURE__ */ React__default.createElement("table", { className: styles.propertyEditorTable }, /* @__PURE__ */ React__default.createElement("thead", null, /* @__PURE__ */ React__default.createElement("tr", null, /* @__PURE__ */ React__default.createElement("th", { className: styles.readOnlyColumnCell }, "Attribute"), /* @__PURE__ */ React__default.createElement("th", null, "Value"))), /* @__PURE__ */ React__default.createElement("tbody", null, Object.keys(properties).map((propName) => /* @__PURE__ */ React__default.createElement("tr", { key: propName }, /* @__PURE__ */ React__default.createElement("th", { className: styles.readOnlyColumnCell }, " ", propName, " "), /* @__PURE__ */ React__default.createElement("td", null, /* @__PURE__ */ React__default.createElement("input", { ...register(propName), className: styles.propertyEditorInput }))))), /* @__PURE__ */ React__default.createElement("tfoot", null, /* @__PURE__ */ React__default.createElement("tr", null, /* @__PURE__ */ React__default.createElement("td", { colSpan: 2 }, /* @__PURE__ */ React__default.createElement("div", { className: styles.buttonsFooter }, /* @__PURE__ */ React__default.createElement("button", { type: "submit", className: styles.primaryButton }, "Save"), /* @__PURE__ */ React__default.createElement(
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Control, UseFormSetValue } from 'react-hook-form';
|
|
3
|
+
export declare const DownshiftAutoComplete: React.FC<{
|
|
4
|
+
suggestions: string[];
|
|
5
|
+
control: Control<any, any>;
|
|
6
|
+
setValue: UseFormSetValue<any>;
|
|
7
|
+
placeholder: string;
|
|
8
|
+
inputName: string;
|
|
9
|
+
autofocus?: boolean;
|
|
10
|
+
initialInputValue: string;
|
|
11
|
+
}>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { useCombobox } from "downshift";
|
|
2
|
+
import React__default from "react";
|
|
3
|
+
import { Controller } from "react-hook-form";
|
|
4
|
+
import styles from "../../../styles/ui.module.css.js";
|
|
5
|
+
import DropDownIcon from "../../../icons/arrow_drop_down.svg.js";
|
|
6
|
+
const MAX_SUGGESTIONS = 20;
|
|
7
|
+
const DownshiftAutoComplete = ({ autofocus, suggestions, control, inputName, placeholder, initialInputValue, setValue }) => {
|
|
8
|
+
const [items, setItems] = React__default.useState(suggestions.slice(0, MAX_SUGGESTIONS));
|
|
9
|
+
const enableAutoComplete = suggestions.length > 0;
|
|
10
|
+
const { isOpen, getToggleButtonProps, getMenuProps, getInputProps, highlightedIndex, getItemProps, selectedItem } = useCombobox({
|
|
11
|
+
initialInputValue,
|
|
12
|
+
onInputValueChange({ inputValue }) {
|
|
13
|
+
inputValue = (inputValue == null ? void 0 : inputValue.toLowerCase()) || "";
|
|
14
|
+
setValue(inputName, inputValue);
|
|
15
|
+
const matchingItems = [];
|
|
16
|
+
for (const suggestion of suggestions) {
|
|
17
|
+
if (suggestion.toLowerCase().includes(inputValue)) {
|
|
18
|
+
matchingItems.push(suggestion);
|
|
19
|
+
if (matchingItems.length >= MAX_SUGGESTIONS) {
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
setItems(matchingItems);
|
|
25
|
+
},
|
|
26
|
+
items,
|
|
27
|
+
itemToString(item) {
|
|
28
|
+
return item ?? "";
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
const dropdownIsVisible = isOpen && items.length > 0;
|
|
32
|
+
return /* @__PURE__ */ React__default.createElement("div", { className: styles.downshiftAutocompleteContainer }, /* @__PURE__ */ React__default.createElement("div", { "data-visible-dropdown": dropdownIsVisible, className: styles.downshiftInputWrapper }, /* @__PURE__ */ React__default.createElement(
|
|
33
|
+
Controller,
|
|
34
|
+
{
|
|
35
|
+
name: inputName,
|
|
36
|
+
control,
|
|
37
|
+
render: ({ field }) => {
|
|
38
|
+
const downshiftSrcProps = getInputProps();
|
|
39
|
+
return /* @__PURE__ */ React__default.createElement(
|
|
40
|
+
"input",
|
|
41
|
+
{
|
|
42
|
+
...downshiftSrcProps,
|
|
43
|
+
name: field.name,
|
|
44
|
+
placeholder,
|
|
45
|
+
className: styles.downshiftInput,
|
|
46
|
+
size: 30,
|
|
47
|
+
"data-editor-dialog": true,
|
|
48
|
+
autoFocus: autofocus
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
), enableAutoComplete && /* @__PURE__ */ React__default.createElement("button", { "aria-label": "toggle menu", type: "button", ...getToggleButtonProps() }, /* @__PURE__ */ React__default.createElement(DropDownIcon, null))), /* @__PURE__ */ React__default.createElement("div", { className: styles.downshiftAutocompleteContainer }, /* @__PURE__ */ React__default.createElement("ul", { ...getMenuProps(), "data-visible": dropdownIsVisible }, items.map((item, index) => /* @__PURE__ */ React__default.createElement(
|
|
54
|
+
"li",
|
|
55
|
+
{
|
|
56
|
+
"data-selected": selectedItem === item,
|
|
57
|
+
"data-highlighted": highlightedIndex === index,
|
|
58
|
+
key: `${item}${index}`,
|
|
59
|
+
...getItemProps({ item, index })
|
|
60
|
+
},
|
|
61
|
+
item
|
|
62
|
+
)))));
|
|
63
|
+
};
|
|
64
|
+
export {
|
|
65
|
+
DownshiftAutoComplete
|
|
66
|
+
};
|
|
@@ -28,7 +28,6 @@ const CmMergeView = ({ oldMarkdown, newMarkdown, onUpdate }) => {
|
|
|
28
28
|
orientation: "a-b",
|
|
29
29
|
revertControls: "a-to-b",
|
|
30
30
|
gutter: true,
|
|
31
|
-
collapseUnchanged: { margin: 2, minSize: 3 },
|
|
32
31
|
a: {
|
|
33
32
|
doc: oldMarkdown,
|
|
34
33
|
extensions: [...COMMON_STATE_CONFIG_EXTENSIONS, EditorState.readOnly.of(true)]
|
|
@@ -46,20 +46,31 @@ const FrontmatterEditor = ({ yaml, onChange }) => {
|
|
|
46
46
|
},
|
|
47
47
|
[onChange, setFrontmatterDialogOpen, removeFrontmatter]
|
|
48
48
|
);
|
|
49
|
-
return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(Dialog.Root, { open: frontmatterDialogOpen, onOpenChange: (open) => setFrontmatterDialogOpen(open) }, /* @__PURE__ */ React__default.createElement(Dialog.Portal, { container: editorRootElementRef == null ? void 0 : editorRootElementRef.current }, /* @__PURE__ */ React__default.createElement(Dialog.Overlay, { className: styles.dialogOverlay }), /* @__PURE__ */ React__default.createElement(Dialog.Content, { className: styles.largeDialogContent, "data-editor-type": "frontmatter" }, /* @__PURE__ */ React__default.createElement(Dialog.Title, { className: styles.dialogTitle }, "Edit document frontmatter"), /* @__PURE__ */ React__default.createElement(
|
|
50
|
-
|
|
51
|
-
})), /* @__PURE__ */ React__default.createElement("tfoot", null, /* @__PURE__ */ React__default.createElement("tr", null, /* @__PURE__ */ React__default.createElement("td", null, /* @__PURE__ */ React__default.createElement(
|
|
52
|
-
"button",
|
|
49
|
+
return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(Dialog.Root, { open: frontmatterDialogOpen, onOpenChange: (open) => setFrontmatterDialogOpen(open) }, /* @__PURE__ */ React__default.createElement(Dialog.Portal, { container: editorRootElementRef == null ? void 0 : editorRootElementRef.current }, /* @__PURE__ */ React__default.createElement(Dialog.Overlay, { className: styles.dialogOverlay }), /* @__PURE__ */ React__default.createElement(Dialog.Content, { className: styles.largeDialogContent, "data-editor-type": "frontmatter" }, /* @__PURE__ */ React__default.createElement(Dialog.Title, { className: styles.dialogTitle }, "Edit document frontmatter"), /* @__PURE__ */ React__default.createElement(
|
|
50
|
+
"form",
|
|
53
51
|
{
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
52
|
+
onSubmit: (e) => {
|
|
53
|
+
void handleSubmit(onSubmit)(e);
|
|
54
|
+
e.nativeEvent.stopImmediatePropagation();
|
|
55
|
+
},
|
|
56
|
+
onReset: () => setFrontmatterDialogOpen(false)
|
|
60
57
|
},
|
|
61
|
-
"
|
|
62
|
-
|
|
58
|
+
/* @__PURE__ */ React__default.createElement("table", { className: styles.propertyEditorTable }, /* @__PURE__ */ React__default.createElement("colgroup", null, /* @__PURE__ */ React__default.createElement("col", null), /* @__PURE__ */ React__default.createElement("col", null), /* @__PURE__ */ React__default.createElement("col", null)), /* @__PURE__ */ React__default.createElement("thead", null, /* @__PURE__ */ React__default.createElement("tr", null, /* @__PURE__ */ React__default.createElement("th", null, "Key"), /* @__PURE__ */ React__default.createElement("th", null, "Value"), /* @__PURE__ */ React__default.createElement("th", null))), /* @__PURE__ */ React__default.createElement("tbody", null, fields.map((item, index) => {
|
|
59
|
+
return /* @__PURE__ */ React__default.createElement("tr", { key: item.id }, /* @__PURE__ */ React__default.createElement("td", null, /* @__PURE__ */ React__default.createElement(TableInput, { ...register(`yamlConfig.${index}.key`, { required: true }), autofocusIfEmpty: true, readOnly })), /* @__PURE__ */ React__default.createElement("td", null, /* @__PURE__ */ React__default.createElement(TableInput, { ...register(`yamlConfig.${index}.value`, { required: true }), readOnly })), /* @__PURE__ */ React__default.createElement("td", null, /* @__PURE__ */ React__default.createElement("button", { type: "button", onClick: () => remove(index), className: styles.iconButton, disabled: readOnly }, /* @__PURE__ */ React__default.createElement(DeleteIcon, null))));
|
|
60
|
+
})), /* @__PURE__ */ React__default.createElement("tfoot", null, /* @__PURE__ */ React__default.createElement("tr", null, /* @__PURE__ */ React__default.createElement("td", null, /* @__PURE__ */ React__default.createElement(
|
|
61
|
+
"button",
|
|
62
|
+
{
|
|
63
|
+
disabled: readOnly,
|
|
64
|
+
className: classNames(styles.primaryButton, styles.smallButton),
|
|
65
|
+
type: "button",
|
|
66
|
+
onClick: () => {
|
|
67
|
+
append({ key: "", value: "" });
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"Add entry"
|
|
71
|
+
))))),
|
|
72
|
+
/* @__PURE__ */ React__default.createElement("div", { style: { display: "flex", justifyContent: "flex-end", gap: "var(--spacing-2)" } }, /* @__PURE__ */ React__default.createElement("button", { type: "submit", className: styles.primaryButton }, "Save"), /* @__PURE__ */ React__default.createElement("button", { type: "reset", className: styles.secondaryButton }, "Cancel"))
|
|
73
|
+
), /* @__PURE__ */ React__default.createElement(Dialog.Close, { asChild: true }, /* @__PURE__ */ React__default.createElement("button", { className: styles.dialogCloseButton, "aria-label": "Close" }, /* @__PURE__ */ React__default.createElement(CloseIcon, null)))))));
|
|
63
74
|
};
|
|
64
75
|
const TableInput = React__default.forwardRef(({ className, autofocusIfEmpty: _, ...props }, ref) => {
|
|
65
76
|
return /* @__PURE__ */ React__default.createElement("input", { className: classNames(styles.propertyEditorInput, className), ...props, ref });
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as Dialog from "@radix-ui/react-dialog";
|
|
2
|
+
import classNames from "classnames";
|
|
3
|
+
import React__default from "react";
|
|
4
|
+
import { useForm } from "react-hook-form";
|
|
5
|
+
import styles from "../../styles/ui.module.css.js";
|
|
6
|
+
import { corePluginHooks } from "../core/index.js";
|
|
7
|
+
import { imagePluginHooks } from "./index.js";
|
|
8
|
+
import { DownshiftAutoComplete } from "../core/ui/DownshiftAutoComplete.js";
|
|
9
|
+
const ImageDialog = () => {
|
|
10
|
+
const [imageAutocompleteSuggestions, state] = imagePluginHooks.useEmitterValues("imageAutocompleteSuggestions", "imageDialogState");
|
|
11
|
+
const saveImage = imagePluginHooks.usePublisher("saveImage");
|
|
12
|
+
const [editorRootElementRef] = corePluginHooks.useEmitterValues("editorRootElementRef");
|
|
13
|
+
const closeImageDialog = imagePluginHooks.usePublisher("closeImageDialog");
|
|
14
|
+
const { register, handleSubmit, control, setValue, reset } = useForm({
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
16
|
+
values: state.type === "editing" ? state.initialValues : {}
|
|
17
|
+
});
|
|
18
|
+
return /* @__PURE__ */ React__default.createElement(
|
|
19
|
+
Dialog.Root,
|
|
20
|
+
{
|
|
21
|
+
open: state.type !== "inactive",
|
|
22
|
+
onOpenChange: (open) => {
|
|
23
|
+
if (!open) {
|
|
24
|
+
closeImageDialog(true);
|
|
25
|
+
reset({ src: "", title: "", altText: "" });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
/* @__PURE__ */ React__default.createElement(Dialog.Portal, { container: editorRootElementRef == null ? void 0 : editorRootElementRef.current }, /* @__PURE__ */ React__default.createElement(Dialog.Overlay, { className: styles.dialogOverlay }), /* @__PURE__ */ React__default.createElement(
|
|
30
|
+
Dialog.Content,
|
|
31
|
+
{
|
|
32
|
+
className: styles.dialogContent,
|
|
33
|
+
onOpenAutoFocus: (e) => {
|
|
34
|
+
e.preventDefault();
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
/* @__PURE__ */ React__default.createElement(
|
|
38
|
+
"form",
|
|
39
|
+
{
|
|
40
|
+
onSubmit: (e) => {
|
|
41
|
+
void handleSubmit(saveImage)(e);
|
|
42
|
+
reset({ src: "", title: "", altText: "" });
|
|
43
|
+
e.nativeEvent.stopImmediatePropagation();
|
|
44
|
+
},
|
|
45
|
+
className: styles.multiFieldForm
|
|
46
|
+
},
|
|
47
|
+
/* @__PURE__ */ React__default.createElement("div", { className: styles.formField }, /* @__PURE__ */ React__default.createElement("label", { htmlFor: "file" }, "Upload an image from your device:"), /* @__PURE__ */ React__default.createElement("input", { type: "file", ...register("file") })),
|
|
48
|
+
/* @__PURE__ */ React__default.createElement("div", { className: styles.formField }, /* @__PURE__ */ React__default.createElement("label", { htmlFor: "src" }, "Or add an image from an URL:"), /* @__PURE__ */ React__default.createElement(
|
|
49
|
+
DownshiftAutoComplete,
|
|
50
|
+
{
|
|
51
|
+
initialInputValue: state.type === "editing" ? state.initialValues.src || "" : "",
|
|
52
|
+
inputName: "src",
|
|
53
|
+
suggestions: imageAutocompleteSuggestions,
|
|
54
|
+
setValue,
|
|
55
|
+
control,
|
|
56
|
+
placeholder: "Select or paste an image src"
|
|
57
|
+
}
|
|
58
|
+
)),
|
|
59
|
+
/* @__PURE__ */ React__default.createElement("div", { className: styles.formField }, /* @__PURE__ */ React__default.createElement("label", { htmlFor: "alt" }, "Alt:"), /* @__PURE__ */ React__default.createElement("input", { type: "text", ...register("altText"), className: styles.textInput })),
|
|
60
|
+
/* @__PURE__ */ React__default.createElement("div", { className: styles.formField }, /* @__PURE__ */ React__default.createElement("label", { htmlFor: "title" }, "Title:"), /* @__PURE__ */ React__default.createElement("input", { type: "text", ...register("title"), className: styles.textInput })),
|
|
61
|
+
/* @__PURE__ */ React__default.createElement("div", { style: { display: "flex", justifyContent: "flex-end", gap: "var(--spacing-2)" } }, /* @__PURE__ */ React__default.createElement("button", { type: "submit", title: "Save", "aria-label": "Save", className: classNames(styles.primaryButton) }, "Save"), /* @__PURE__ */ React__default.createElement(Dialog.Close, { asChild: true }, /* @__PURE__ */ React__default.createElement("button", { type: "reset", title: "Cancel", "aria-label": "Cancel", className: classNames(styles.secondaryButton) }, "Cancel")))
|
|
62
|
+
)
|
|
63
|
+
))
|
|
64
|
+
);
|
|
65
|
+
};
|
|
66
|
+
export {
|
|
67
|
+
ImageDialog
|
|
68
|
+
};
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
export interface ImageEditorProps {
|
|
3
3
|
nodeKey: string;
|
|
4
4
|
src: string;
|
|
5
|
+
alt?: string;
|
|
5
6
|
title?: string;
|
|
6
7
|
width: number | 'inherit';
|
|
7
8
|
height: number | 'inherit';
|
|
8
9
|
}
|
|
9
|
-
export declare function ImageEditor({ src, title, nodeKey, width, height }: ImageEditorProps): JSX.Element | null;
|
|
10
|
+
export declare function ImageEditor({ src, title, alt, nodeKey, width, height }: ImageEditorProps): JSX.Element | null;
|
|
@@ -2,12 +2,13 @@ import React__default from "react";
|
|
|
2
2
|
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext.js";
|
|
3
3
|
import { useLexicalNodeSelection } from "@lexical/react/useLexicalNodeSelection.js";
|
|
4
4
|
import { mergeRegister } from "@lexical/utils";
|
|
5
|
+
import classNames from "classnames";
|
|
5
6
|
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";
|
|
7
|
+
import { imagePluginHooks } from "./index.js";
|
|
8
|
+
import SettingsIcon from "../../icons/settings.svg.js";
|
|
6
9
|
import styles from "../../styles/ui.module.css.js";
|
|
7
|
-
import classNames from "classnames";
|
|
8
10
|
import { $isImageNode } from "./ImageNode.js";
|
|
9
11
|
import ImageResizer from "./ImageResizer.js";
|
|
10
|
-
import { imagePluginHooks } from "./index.js";
|
|
11
12
|
const imageCache = /* @__PURE__ */ new Set();
|
|
12
13
|
function useSuspenseImage(src) {
|
|
13
14
|
if (!imageCache.has(src)) {
|
|
@@ -23,6 +24,7 @@ function useSuspenseImage(src) {
|
|
|
23
24
|
}
|
|
24
25
|
function LazyImage({
|
|
25
26
|
title,
|
|
27
|
+
alt,
|
|
26
28
|
className,
|
|
27
29
|
imageRef,
|
|
28
30
|
src,
|
|
@@ -30,9 +32,21 @@ function LazyImage({
|
|
|
30
32
|
height
|
|
31
33
|
}) {
|
|
32
34
|
useSuspenseImage(src);
|
|
33
|
-
return /* @__PURE__ */ React__default.createElement(
|
|
35
|
+
return /* @__PURE__ */ React__default.createElement(
|
|
36
|
+
"img",
|
|
37
|
+
{
|
|
38
|
+
className: className || void 0,
|
|
39
|
+
alt,
|
|
40
|
+
src,
|
|
41
|
+
title,
|
|
42
|
+
ref: imageRef,
|
|
43
|
+
draggable: "false",
|
|
44
|
+
width,
|
|
45
|
+
height
|
|
46
|
+
}
|
|
47
|
+
);
|
|
34
48
|
}
|
|
35
|
-
function ImageEditor({ src, title, nodeKey, width, height }) {
|
|
49
|
+
function ImageEditor({ src, title, alt, nodeKey, width, height }) {
|
|
36
50
|
const imageRef = React__default.useRef(null);
|
|
37
51
|
const buttonRef = React__default.useRef(null);
|
|
38
52
|
const [isSelected, setSelected, clearSelection] = useLexicalNodeSelection(nodeKey);
|
|
@@ -43,6 +57,7 @@ function ImageEditor({ src, title, nodeKey, width, height }) {
|
|
|
43
57
|
const [disableImageResize] = imagePluginHooks.useEmitterValues("disableImageResize");
|
|
44
58
|
const [imagePreviewHandler] = imagePluginHooks.useEmitterValues("imagePreviewHandler");
|
|
45
59
|
const [imageSource, setImageSource] = React__default.useState(null);
|
|
60
|
+
const openEditImageDialog = imagePluginHooks.usePublisher("openEditImageDialog");
|
|
46
61
|
const onDelete = React__default.useCallback(
|
|
47
62
|
(payload) => {
|
|
48
63
|
if (isSelected && $isNodeSelection($getSelection())) {
|
|
@@ -183,9 +198,27 @@ function ImageEditor({ src, title, nodeKey, width, height }) {
|
|
|
183
198
|
}),
|
|
184
199
|
src: imageSource,
|
|
185
200
|
title: title || "",
|
|
201
|
+
alt: alt || "",
|
|
186
202
|
imageRef
|
|
187
203
|
}
|
|
188
|
-
)), draggable && isFocused && !disableImageResize && /* @__PURE__ */ React__default.createElement(ImageResizer, { editor, imageRef, onResizeStart, onResizeEnd })
|
|
204
|
+
)), draggable && isFocused && !disableImageResize && /* @__PURE__ */ React__default.createElement(ImageResizer, { editor, imageRef, onResizeStart, onResizeEnd }), /* @__PURE__ */ React__default.createElement(
|
|
205
|
+
"button",
|
|
206
|
+
{
|
|
207
|
+
className: classNames(styles.iconButton, styles.editImageButton),
|
|
208
|
+
title: "Edit image",
|
|
209
|
+
onClick: () => {
|
|
210
|
+
openEditImageDialog({
|
|
211
|
+
nodeKey,
|
|
212
|
+
initialValues: {
|
|
213
|
+
src: imageSource,
|
|
214
|
+
title: title || "",
|
|
215
|
+
altText: alt || ""
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
/* @__PURE__ */ React__default.createElement(SettingsIcon, null)
|
|
221
|
+
))) : null;
|
|
189
222
|
}
|
|
190
223
|
export {
|
|
191
224
|
ImageEditor
|
|
@@ -39,6 +39,8 @@ export declare class ImageNode extends DecoratorNode<JSX.Element> {
|
|
|
39
39
|
getWidth(): 'inherit' | number;
|
|
40
40
|
hasExplicitDimensions(): boolean;
|
|
41
41
|
setTitle(title: string | undefined): void;
|
|
42
|
+
setSrc(src: string): void;
|
|
43
|
+
setAltText(altText: string | undefined): void;
|
|
42
44
|
decorate(_parentEditor: LexicalEditor): JSX.Element;
|
|
43
45
|
}
|
|
44
46
|
/**
|
|
@@ -30,7 +30,7 @@ class ImageNode extends DecoratorNode {
|
|
|
30
30
|
this.__height = height || "inherit";
|
|
31
31
|
}
|
|
32
32
|
static getType() {
|
|
33
|
-
return "
|
|
33
|
+
return "icage";
|
|
34
34
|
}
|
|
35
35
|
static clone(node) {
|
|
36
36
|
return new ImageNode(node.__src, node.__altText, node.__title, node.__width, node.__height, node.__key);
|
|
@@ -118,8 +118,24 @@ class ImageNode extends DecoratorNode {
|
|
|
118
118
|
setTitle(title) {
|
|
119
119
|
this.getWritable().__title = title;
|
|
120
120
|
}
|
|
121
|
+
setSrc(src) {
|
|
122
|
+
this.getWritable().__src = src;
|
|
123
|
+
}
|
|
124
|
+
setAltText(altText) {
|
|
125
|
+
this.getWritable().__altText = altText ?? "";
|
|
126
|
+
}
|
|
121
127
|
decorate(_parentEditor) {
|
|
122
|
-
return /* @__PURE__ */ React__default.createElement(
|
|
128
|
+
return /* @__PURE__ */ React__default.createElement(
|
|
129
|
+
ImageEditor,
|
|
130
|
+
{
|
|
131
|
+
src: this.getSrc(),
|
|
132
|
+
title: this.getTitle(),
|
|
133
|
+
nodeKey: this.getKey(),
|
|
134
|
+
width: this.__width,
|
|
135
|
+
height: this.__height,
|
|
136
|
+
alt: this.__altText
|
|
137
|
+
}
|
|
138
|
+
);
|
|
123
139
|
}
|
|
124
140
|
}
|
|
125
141
|
function $createImageNode(options) {
|
|
@@ -15,6 +15,23 @@ import { CreateImageNodeOptions } from './ImageNode';
|
|
|
15
15
|
export * from './ImageNode';
|
|
16
16
|
export type ImageUploadHandler = ((image: File) => Promise<string>) | null;
|
|
17
17
|
export type ImagePreviewHandler = ((imageSource: string) => Promise<string>) | null;
|
|
18
|
+
export interface InsertImageFormValues {
|
|
19
|
+
src?: string;
|
|
20
|
+
altText?: string;
|
|
21
|
+
title?: string;
|
|
22
|
+
file: FileList;
|
|
23
|
+
}
|
|
24
|
+
type InactiveImageDialogState = {
|
|
25
|
+
type: 'inactive';
|
|
26
|
+
};
|
|
27
|
+
type NewImageDialogState = {
|
|
28
|
+
type: 'new';
|
|
29
|
+
};
|
|
30
|
+
type EditingImageDialogState = {
|
|
31
|
+
type: 'editing';
|
|
32
|
+
nodeKey: string;
|
|
33
|
+
initialValues: Omit<InsertImageFormValues, 'file'>;
|
|
34
|
+
};
|
|
18
35
|
/** @internal */
|
|
19
36
|
export declare const imageSystem: SystemSpec<[SystemSpec<[], (r: Realm) => {
|
|
20
37
|
activeEditor: RealmNode<LexicalEditor | null>;
|
|
@@ -127,10 +144,15 @@ export declare const imageSystem: SystemSpec<[SystemSpec<[], (r: Realm) => {
|
|
|
127
144
|
insertDecoratorNode: RealmNode<() => DecoratorNode<unknown>>;
|
|
128
145
|
onBlur: RealmNode<FocusEvent>;
|
|
129
146
|
}]) => {
|
|
147
|
+
imageDialogState: RealmNode<InactiveImageDialogState | NewImageDialogState | EditingImageDialogState>;
|
|
148
|
+
saveImage: RealmNode<InsertImageFormValues>;
|
|
149
|
+
openNewImageDialog: RealmNode<true>;
|
|
150
|
+
openEditImageDialog: RealmNode<Omit<EditingImageDialogState, "type">>;
|
|
151
|
+
closeImageDialog: RealmNode<true>;
|
|
130
152
|
imageUploadHandler: RealmNode<ImageUploadHandler>;
|
|
131
153
|
imageAutocompleteSuggestions: RealmNode<string[]>;
|
|
132
154
|
disableImageResize: RealmNode<boolean>;
|
|
133
|
-
insertImage: RealmNode<
|
|
155
|
+
insertImage: RealmNode<InsertImageFormValues>;
|
|
134
156
|
imagePreviewHandler: RealmNode<ImagePreviewHandler>;
|
|
135
157
|
}>;
|
|
136
158
|
interface ImagePluginParams {
|
|
@@ -252,19 +274,29 @@ imagePlugin: PluginConstructor<SystemSpec<[SystemSpec<[], (r: Realm) => {
|
|
|
252
274
|
insertDecoratorNode: RealmNode<() => DecoratorNode<unknown>>;
|
|
253
275
|
onBlur: RealmNode<FocusEvent>;
|
|
254
276
|
}]) => {
|
|
277
|
+
imageDialogState: RealmNode<InactiveImageDialogState | NewImageDialogState | EditingImageDialogState>;
|
|
278
|
+
saveImage: RealmNode<InsertImageFormValues>;
|
|
279
|
+
openNewImageDialog: RealmNode<true>;
|
|
280
|
+
openEditImageDialog: RealmNode<Omit<EditingImageDialogState, "type">>;
|
|
281
|
+
closeImageDialog: RealmNode<true>;
|
|
255
282
|
imageUploadHandler: RealmNode<ImageUploadHandler>;
|
|
256
283
|
imageAutocompleteSuggestions: RealmNode<string[]>;
|
|
257
284
|
disableImageResize: RealmNode<boolean>;
|
|
258
|
-
insertImage: RealmNode<
|
|
285
|
+
insertImage: RealmNode<InsertImageFormValues>;
|
|
259
286
|
imagePreviewHandler: RealmNode<ImagePreviewHandler>;
|
|
260
287
|
}>, ImagePluginParams>,
|
|
261
288
|
/** @internal */
|
|
262
289
|
imagePluginHooks: {
|
|
263
290
|
useRealmContext: () => TypedRealm<{
|
|
291
|
+
imageDialogState: RealmNode<InactiveImageDialogState | NewImageDialogState | EditingImageDialogState>;
|
|
292
|
+
saveImage: RealmNode<InsertImageFormValues>;
|
|
293
|
+
openNewImageDialog: RealmNode<true>;
|
|
294
|
+
openEditImageDialog: RealmNode<Omit<EditingImageDialogState, "type">>;
|
|
295
|
+
closeImageDialog: RealmNode<true>;
|
|
264
296
|
imageUploadHandler: RealmNode<ImageUploadHandler>;
|
|
265
297
|
imageAutocompleteSuggestions: RealmNode<string[]>;
|
|
266
298
|
disableImageResize: RealmNode<boolean>;
|
|
267
|
-
insertImage: RealmNode<
|
|
299
|
+
insertImage: RealmNode<InsertImageFormValues>;
|
|
268
300
|
imagePreviewHandler: RealmNode<ImagePreviewHandler>;
|
|
269
301
|
} & {
|
|
270
302
|
activeEditor: RealmNode<LexicalEditor | null>;
|
|
@@ -322,11 +354,16 @@ imagePluginHooks: {
|
|
|
322
354
|
insertDecoratorNode: RealmNode<() => DecoratorNode<unknown>>;
|
|
323
355
|
onBlur: RealmNode<FocusEvent>;
|
|
324
356
|
}>;
|
|
325
|
-
useEmitter: <K extends "jsxComponentDescriptors" | "jsxIsAvailable" | "toMarkdownOptions" | "toMarkdownExtensions" | "mdastExtensions" | "syntaxExtensions" | "markdown" | "activeEditor" | "inFocus" | "historyState" | "currentSelection" | "initialRootEditorState" | "rootEditor" | "createRootEditorSubscription" | "createActiveEditorSubscription" | "importVisitors" | "usedLexicalNodes" | "addImportVisitor" | "addLexicalNode" | "addSyntaxExtension" | "addMdastExtension" | "addToMarkdownExtension" | "addExportVisitor" | "exportVisitors" | "initialMarkdown" | "setMarkdown" | "editorRootElementRef" | "contentEditableClassName" | "placeholder" | "autoFocus" | "readOnly" | "composerChildren" | "addComposerChild" | "topAreaChildren" | "addTopAreaChild" | "nestedEditorChildren" | "addNestedEditorChild" | "editorWrappers" | "addEditorWrapper" | "currentFormat" | "editorInFocus" | "applyFormat" | "currentBlockType" | "applyBlockType" | "convertSelectionToNode" | "insertDecoratorNode" | "onBlur" | "imageUploadHandler" | "imageAutocompleteSuggestions" | "disableImageResize" | "insertImage" | "imagePreviewHandler">(key: K, callback: (value: ValueForKey<{
|
|
357
|
+
useEmitter: <K extends "jsxComponentDescriptors" | "jsxIsAvailable" | "toMarkdownOptions" | "toMarkdownExtensions" | "mdastExtensions" | "syntaxExtensions" | "markdown" | "activeEditor" | "inFocus" | "historyState" | "currentSelection" | "initialRootEditorState" | "rootEditor" | "createRootEditorSubscription" | "createActiveEditorSubscription" | "importVisitors" | "usedLexicalNodes" | "addImportVisitor" | "addLexicalNode" | "addSyntaxExtension" | "addMdastExtension" | "addToMarkdownExtension" | "addExportVisitor" | "exportVisitors" | "initialMarkdown" | "setMarkdown" | "editorRootElementRef" | "contentEditableClassName" | "placeholder" | "autoFocus" | "readOnly" | "composerChildren" | "addComposerChild" | "topAreaChildren" | "addTopAreaChild" | "nestedEditorChildren" | "addNestedEditorChild" | "editorWrappers" | "addEditorWrapper" | "currentFormat" | "editorInFocus" | "applyFormat" | "currentBlockType" | "applyBlockType" | "convertSelectionToNode" | "insertDecoratorNode" | "onBlur" | "imageDialogState" | "saveImage" | "openNewImageDialog" | "openEditImageDialog" | "closeImageDialog" | "imageUploadHandler" | "imageAutocompleteSuggestions" | "disableImageResize" | "insertImage" | "imagePreviewHandler">(key: K, callback: (value: ValueForKey<{
|
|
358
|
+
imageDialogState: RealmNode<InactiveImageDialogState | NewImageDialogState | EditingImageDialogState>;
|
|
359
|
+
saveImage: RealmNode<InsertImageFormValues>;
|
|
360
|
+
openNewImageDialog: RealmNode<true>;
|
|
361
|
+
openEditImageDialog: RealmNode<Omit<EditingImageDialogState, "type">>;
|
|
362
|
+
closeImageDialog: RealmNode<true>;
|
|
326
363
|
imageUploadHandler: RealmNode<ImageUploadHandler>;
|
|
327
364
|
imageAutocompleteSuggestions: RealmNode<string[]>;
|
|
328
365
|
disableImageResize: RealmNode<boolean>;
|
|
329
|
-
insertImage: RealmNode<
|
|
366
|
+
insertImage: RealmNode<InsertImageFormValues>;
|
|
330
367
|
imagePreviewHandler: RealmNode<ImagePreviewHandler>;
|
|
331
368
|
} & {
|
|
332
369
|
activeEditor: RealmNode<LexicalEditor | null>;
|
|
@@ -385,10 +422,15 @@ imagePluginHooks: {
|
|
|
385
422
|
onBlur: RealmNode<FocusEvent>;
|
|
386
423
|
}, K>) => void) => void;
|
|
387
424
|
useEmitterValues: <K_1 extends SystemKeys<{
|
|
425
|
+
imageDialogState: RealmNode<InactiveImageDialogState | NewImageDialogState | EditingImageDialogState>;
|
|
426
|
+
saveImage: RealmNode<InsertImageFormValues>;
|
|
427
|
+
openNewImageDialog: RealmNode<true>;
|
|
428
|
+
openEditImageDialog: RealmNode<Omit<EditingImageDialogState, "type">>;
|
|
429
|
+
closeImageDialog: RealmNode<true>;
|
|
388
430
|
imageUploadHandler: RealmNode<ImageUploadHandler>;
|
|
389
431
|
imageAutocompleteSuggestions: RealmNode<string[]>;
|
|
390
432
|
disableImageResize: RealmNode<boolean>;
|
|
391
|
-
insertImage: RealmNode<
|
|
433
|
+
insertImage: RealmNode<InsertImageFormValues>;
|
|
392
434
|
imagePreviewHandler: RealmNode<ImagePreviewHandler>;
|
|
393
435
|
} & {
|
|
394
436
|
activeEditor: RealmNode<LexicalEditor | null>;
|
|
@@ -446,10 +488,15 @@ imagePluginHooks: {
|
|
|
446
488
|
insertDecoratorNode: RealmNode<() => DecoratorNode<unknown>>;
|
|
447
489
|
onBlur: RealmNode<FocusEvent>;
|
|
448
490
|
}>>(...keys: K_1) => ValuesForKeys<{
|
|
491
|
+
imageDialogState: RealmNode<InactiveImageDialogState | NewImageDialogState | EditingImageDialogState>;
|
|
492
|
+
saveImage: RealmNode<InsertImageFormValues>;
|
|
493
|
+
openNewImageDialog: RealmNode<true>;
|
|
494
|
+
openEditImageDialog: RealmNode<Omit<EditingImageDialogState, "type">>;
|
|
495
|
+
closeImageDialog: RealmNode<true>;
|
|
449
496
|
imageUploadHandler: RealmNode<ImageUploadHandler>;
|
|
450
497
|
imageAutocompleteSuggestions: RealmNode<string[]>;
|
|
451
498
|
disableImageResize: RealmNode<boolean>;
|
|
452
|
-
insertImage: RealmNode<
|
|
499
|
+
insertImage: RealmNode<InsertImageFormValues>;
|
|
453
500
|
imagePreviewHandler: RealmNode<ImagePreviewHandler>;
|
|
454
501
|
} & {
|
|
455
502
|
activeEditor: RealmNode<LexicalEditor | null>;
|
|
@@ -508,10 +555,15 @@ imagePluginHooks: {
|
|
|
508
555
|
onBlur: RealmNode<FocusEvent>;
|
|
509
556
|
}, K_1>;
|
|
510
557
|
usePubKeys: () => (values: SystemDict<{
|
|
558
|
+
imageDialogState: RealmNode<InactiveImageDialogState | NewImageDialogState | EditingImageDialogState>;
|
|
559
|
+
saveImage: RealmNode<InsertImageFormValues>;
|
|
560
|
+
openNewImageDialog: RealmNode<true>;
|
|
561
|
+
openEditImageDialog: RealmNode<Omit<EditingImageDialogState, "type">>;
|
|
562
|
+
closeImageDialog: RealmNode<true>;
|
|
511
563
|
imageUploadHandler: RealmNode<ImageUploadHandler>;
|
|
512
564
|
imageAutocompleteSuggestions: RealmNode<string[]>;
|
|
513
565
|
disableImageResize: RealmNode<boolean>;
|
|
514
|
-
insertImage: RealmNode<
|
|
566
|
+
insertImage: RealmNode<InsertImageFormValues>;
|
|
515
567
|
imagePreviewHandler: RealmNode<ImagePreviewHandler>;
|
|
516
568
|
} & {
|
|
517
569
|
activeEditor: RealmNode<LexicalEditor | null>;
|
|
@@ -569,11 +621,16 @@ imagePluginHooks: {
|
|
|
569
621
|
insertDecoratorNode: RealmNode<() => DecoratorNode<unknown>>;
|
|
570
622
|
onBlur: RealmNode<FocusEvent>;
|
|
571
623
|
}>) => void;
|
|
572
|
-
usePublisher: <K_2 extends "jsxComponentDescriptors" | "jsxIsAvailable" | "toMarkdownOptions" | "toMarkdownExtensions" | "mdastExtensions" | "syntaxExtensions" | "markdown" | "activeEditor" | "inFocus" | "historyState" | "currentSelection" | "initialRootEditorState" | "rootEditor" | "createRootEditorSubscription" | "createActiveEditorSubscription" | "importVisitors" | "usedLexicalNodes" | "addImportVisitor" | "addLexicalNode" | "addSyntaxExtension" | "addMdastExtension" | "addToMarkdownExtension" | "addExportVisitor" | "exportVisitors" | "initialMarkdown" | "setMarkdown" | "editorRootElementRef" | "contentEditableClassName" | "placeholder" | "autoFocus" | "readOnly" | "composerChildren" | "addComposerChild" | "topAreaChildren" | "addTopAreaChild" | "nestedEditorChildren" | "addNestedEditorChild" | "editorWrappers" | "addEditorWrapper" | "currentFormat" | "editorInFocus" | "applyFormat" | "currentBlockType" | "applyBlockType" | "convertSelectionToNode" | "insertDecoratorNode" | "onBlur" | "imageUploadHandler" | "imageAutocompleteSuggestions" | "disableImageResize" | "insertImage" | "imagePreviewHandler">(key: K_2) => (value: ValueForKey<{
|
|
624
|
+
usePublisher: <K_2 extends "jsxComponentDescriptors" | "jsxIsAvailable" | "toMarkdownOptions" | "toMarkdownExtensions" | "mdastExtensions" | "syntaxExtensions" | "markdown" | "activeEditor" | "inFocus" | "historyState" | "currentSelection" | "initialRootEditorState" | "rootEditor" | "createRootEditorSubscription" | "createActiveEditorSubscription" | "importVisitors" | "usedLexicalNodes" | "addImportVisitor" | "addLexicalNode" | "addSyntaxExtension" | "addMdastExtension" | "addToMarkdownExtension" | "addExportVisitor" | "exportVisitors" | "initialMarkdown" | "setMarkdown" | "editorRootElementRef" | "contentEditableClassName" | "placeholder" | "autoFocus" | "readOnly" | "composerChildren" | "addComposerChild" | "topAreaChildren" | "addTopAreaChild" | "nestedEditorChildren" | "addNestedEditorChild" | "editorWrappers" | "addEditorWrapper" | "currentFormat" | "editorInFocus" | "applyFormat" | "currentBlockType" | "applyBlockType" | "convertSelectionToNode" | "insertDecoratorNode" | "onBlur" | "imageDialogState" | "saveImage" | "openNewImageDialog" | "openEditImageDialog" | "closeImageDialog" | "imageUploadHandler" | "imageAutocompleteSuggestions" | "disableImageResize" | "insertImage" | "imagePreviewHandler">(key: K_2) => (value: ValueForKey<{
|
|
625
|
+
imageDialogState: RealmNode<InactiveImageDialogState | NewImageDialogState | EditingImageDialogState>;
|
|
626
|
+
saveImage: RealmNode<InsertImageFormValues>;
|
|
627
|
+
openNewImageDialog: RealmNode<true>;
|
|
628
|
+
openEditImageDialog: RealmNode<Omit<EditingImageDialogState, "type">>;
|
|
629
|
+
closeImageDialog: RealmNode<true>;
|
|
573
630
|
imageUploadHandler: RealmNode<ImageUploadHandler>;
|
|
574
631
|
imageAutocompleteSuggestions: RealmNode<string[]>;
|
|
575
632
|
disableImageResize: RealmNode<boolean>;
|
|
576
|
-
insertImage: RealmNode<
|
|
633
|
+
insertImage: RealmNode<InsertImageFormValues>;
|
|
577
634
|
imagePreviewHandler: RealmNode<ImagePreviewHandler>;
|
|
578
635
|
} & {
|
|
579
636
|
activeEditor: RealmNode<LexicalEditor | null>;
|