@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.
@@ -1,10 +1,11 @@
1
1
  import { $wrapNodeInElement } from "@lexical/utils";
2
- import { $insertNodes, $isRootOrShadowRoot, $createParagraphNode, COMMAND_PRIORITY_EDITOR, DRAGSTART_COMMAND, COMMAND_PRIORITY_HIGH, DRAGOVER_COMMAND, COMMAND_PRIORITY_LOW, DROP_COMMAND, PASTE_COMMAND, COMMAND_PRIORITY_CRITICAL, createCommand, $createRangeSelection, $setSelection, $getSelection, $isNodeSelection } from "lexical";
2
+ import { $getNodeByKey, $insertNodes, $isRootOrShadowRoot, $createParagraphNode, COMMAND_PRIORITY_EDITOR, DRAGSTART_COMMAND, COMMAND_PRIORITY_HIGH, DRAGOVER_COMMAND, COMMAND_PRIORITY_LOW, DROP_COMMAND, PASTE_COMMAND, COMMAND_PRIORITY_CRITICAL, createCommand, $createRangeSelection, $setSelection, $getSelection, $isNodeSelection } from "lexical";
3
3
  import { coreSystem } from "../core/index.js";
4
4
  import { $createImageNode, $isImageNode, ImageNode } from "./ImageNode.js";
5
5
  import { LexicalImageVisitor } from "./LexicalImageVisitor.js";
6
6
  import { MdastImageVisitor, MdastHtmlImageVisitor, MdastJsxImageVisitor } from "./MdastImageVisitor.js";
7
7
  import { CAN_USE_DOM } from "../../utils/detectMac.js";
8
+ import { ImageDialog } from "./ImageDialog.js";
8
9
  import { system } from "../../gurx/realmFactory.js";
9
10
  import { realmPlugin } from "../../gurx/react.js";
10
11
  const imageSystem = system(
@@ -14,15 +15,51 @@ const imageSystem = system(
14
15
  const disableImageResize = r.node(false);
15
16
  const imageUploadHandler = r.node(null);
16
17
  const imagePreviewHandler = r.node(null);
17
- r.sub(r.pipe(insertImage, r.o.withLatestFrom(rootEditor)), ([src, theEditor]) => {
18
- theEditor == null ? void 0 : theEditor.update(() => {
19
- const imageNode = $createImageNode({ altText: "", src, title: "" });
20
- $insertNodes([imageNode]);
21
- if ($isRootOrShadowRoot(imageNode.getParentOrThrow())) {
22
- $wrapNodeInElement(imageNode, $createParagraphNode).selectEnd();
18
+ const imageDialogState = r.node({ type: "inactive" });
19
+ const openNewImageDialog = r.node();
20
+ const openEditImageDialog = r.node();
21
+ const closeImageDialog = r.node();
22
+ const saveImage = r.node();
23
+ r.link(r.pipe(closeImageDialog, r.o.mapTo({ type: "inactive" })), imageDialogState);
24
+ r.link(r.pipe(openNewImageDialog, r.o.mapTo({ type: "new" })), imageDialogState);
25
+ r.link(
26
+ r.pipe(
27
+ openEditImageDialog,
28
+ r.o.map((payload) => ({ type: "editing", ...payload }))
29
+ ),
30
+ imageDialogState
31
+ );
32
+ r.sub(
33
+ r.pipe(saveImage, r.o.withLatestFrom(rootEditor, imageUploadHandler, imageDialogState)),
34
+ ([values, theEditor, imageUploadHandler2, dialogState]) => {
35
+ const handler = dialogState.type === "editing" ? (src) => {
36
+ theEditor == null ? void 0 : theEditor.update(() => {
37
+ const { nodeKey } = dialogState;
38
+ const imageNode = $getNodeByKey(nodeKey);
39
+ imageNode.setTitle(values.title);
40
+ imageNode.setAltText(values.altText);
41
+ imageNode.setSrc(src);
42
+ });
43
+ r.pub(imageDialogState, { type: "inactive" });
44
+ } : (src) => {
45
+ theEditor == null ? void 0 : theEditor.update(() => {
46
+ const imageNode = $createImageNode({ altText: values.altText ?? "", src, title: values.title ?? "" });
47
+ $insertNodes([imageNode]);
48
+ if ($isRootOrShadowRoot(imageNode.getParentOrThrow())) {
49
+ $wrapNodeInElement(imageNode, $createParagraphNode).selectEnd();
50
+ }
51
+ });
52
+ r.pub(imageDialogState, { type: "inactive" });
53
+ };
54
+ if (values.file.length > 0) {
55
+ imageUploadHandler2 == null ? void 0 : imageUploadHandler2(values.file.item(0)).then(handler).catch((e) => {
56
+ throw e;
57
+ });
58
+ } else if (values.src) {
59
+ handler(values.src);
23
60
  }
24
- });
25
- });
61
+ }
62
+ );
26
63
  r.sub(rootEditor, (editor) => {
27
64
  editor == null ? void 0 : editor.registerCommand(
28
65
  INSERT_IMAGE_COMMAND,
@@ -73,7 +110,10 @@ const imageSystem = system(
73
110
  const imageUploadHandlerValue = r.getValue(imageUploadHandler);
74
111
  Promise.all(cbPayload.map((file) => imageUploadHandlerValue(file.getAsFile()))).then((urls) => {
75
112
  urls.forEach((url) => {
76
- r.pub(insertImage, url);
113
+ editor.dispatchCommand(INSERT_IMAGE_COMMAND, {
114
+ src: url,
115
+ altText: ""
116
+ });
77
117
  });
78
118
  }).catch((e) => {
79
119
  throw e;
@@ -84,6 +124,11 @@ const imageSystem = system(
84
124
  );
85
125
  });
86
126
  return {
127
+ imageDialogState,
128
+ saveImage,
129
+ openNewImageDialog,
130
+ openEditImageDialog,
131
+ closeImageDialog,
87
132
  imageUploadHandler,
88
133
  imageAutocompleteSuggestions,
89
134
  disableImageResize,
@@ -113,6 +158,7 @@ const [
113
158
  realm.pubKey("addImportVisitor", MdastJsxImageVisitor);
114
159
  realm.pubKey("addLexicalNode", ImageNode);
115
160
  realm.pubKey("addExportVisitor", LexicalImageVisitor);
161
+ realm.pubKey("addComposerChild", ImageDialog);
116
162
  }
117
163
  });
118
164
  const getDOMSelection = (targetWindow) => CAN_USE_DOM ? (targetWindow || window).getSelection() : null;
@@ -2,12 +2,15 @@ import React from 'react';
2
2
  import { LexicalCommand } from 'lexical';
3
3
  export declare const OPEN_LINK_DIALOG: LexicalCommand<undefined>;
4
4
  interface LinkEditFormProps {
5
- initialUrl: string;
6
- initialTitle: string;
7
- onSubmit: (link: [string, string]) => void;
5
+ url: string;
6
+ title: string;
7
+ onSubmit: (link: {
8
+ url: string;
9
+ title: string;
10
+ }) => void;
8
11
  onCancel: () => void;
9
12
  linkAutocompleteSuggestions: string[];
10
13
  }
11
- export declare function LinkEditForm({ initialUrl, initialTitle, onSubmit, onCancel, linkAutocompleteSuggestions }: LinkEditFormProps): React.JSX.Element;
14
+ export declare function LinkEditForm({ url, title, onSubmit, onCancel, linkAutocompleteSuggestions }: LinkEditFormProps): React.JSX.Element;
12
15
  export declare const LinkDialog: React.FC;
13
16
  export {};
@@ -7,75 +7,51 @@ import CopyIcon from "../../icons/content_copy.svg.js";
7
7
  import EditIcon from "../../icons/edit.svg.js";
8
8
  import LinkOffIcon from "../../icons/link_off.svg.js";
9
9
  import OpenInNewIcon from "../../icons/open_in_new.svg.js";
10
- import DropDownIcon from "../../icons/arrow_drop_down.svg.js";
11
10
  import classNames from "classnames";
12
- import { useCombobox } from "downshift";
13
11
  import styles from "../../styles/ui.module.css.js";
14
12
  import { corePluginHooks } from "../core/index.js";
15
13
  import { linkDialogPluginHooks } from "./index.js";
14
+ import { useForm } from "react-hook-form";
15
+ import { DownshiftAutoComplete } from "../core/ui/DownshiftAutoComplete.js";
16
16
  createCommand();
17
- const MAX_SUGGESTIONS = 20;
18
- function LinkEditForm({ initialUrl, initialTitle, onSubmit, onCancel, linkAutocompleteSuggestions }) {
19
- const [items, setItems] = React__default.useState(linkAutocompleteSuggestions.slice(0, MAX_SUGGESTIONS));
20
- const [title, setTitle] = React__default.useState(initialTitle);
21
- const { isOpen, getToggleButtonProps, getMenuProps, getInputProps, highlightedIndex, getItemProps, selectedItem, inputValue } = useCombobox({
22
- initialInputValue: initialUrl,
23
- onInputValueChange({ inputValue: inputValue2 }) {
24
- inputValue2 = (inputValue2 == null ? void 0 : inputValue2.toLowerCase()) || "";
25
- const matchingItems = [];
26
- for (const url of linkAutocompleteSuggestions) {
27
- if (url.toLowerCase().includes(inputValue2)) {
28
- matchingItems.push(url);
29
- if (matchingItems.length >= MAX_SUGGESTIONS) {
30
- break;
31
- }
32
- }
33
- }
34
- setItems(matchingItems);
35
- },
36
- items,
37
- itemToString(item) {
38
- return item ?? "";
17
+ function LinkEditForm({ url, title, onSubmit, onCancel, linkAutocompleteSuggestions }) {
18
+ const {
19
+ register,
20
+ handleSubmit,
21
+ control,
22
+ setValue,
23
+ reset: _
24
+ } = useForm({
25
+ values: {
26
+ url,
27
+ title
39
28
  }
40
29
  });
41
- const onSubmitEH = (e) => {
42
- e.preventDefault();
43
- onSubmit([inputValue, title]);
44
- };
45
- const onKeyDownEH = React__default.useCallback(
46
- (e) => {
47
- var _a;
48
- if (e.key === "Escape") {
49
- (_a = e.target.form) == null ? void 0 : _a.reset();
50
- } else if (e.key === "Enter" && (!isOpen || items.length === 0)) {
51
- e.preventDefault();
52
- onSubmit([e.target.value, title]);
53
- }
54
- },
55
- [isOpen, items, onSubmit, title]
56
- );
57
- const handleSaveClick = (event) => {
58
- event.stopPropagation();
59
- };
60
- const downshiftInputProps = getInputProps();
61
- const inputProps = {
62
- ...downshiftInputProps,
63
- onKeyDown: (e) => {
64
- onKeyDownEH(e);
65
- downshiftInputProps.onKeyDown(e);
66
- }
67
- };
68
- const dropdownIsVisible = isOpen && items.length > 0;
69
- return /* @__PURE__ */ React__default.createElement("form", { onSubmit: onSubmitEH, onReset: onCancel, className: classNames(styles.linkDialogEditForm) }, /* @__PURE__ */ React__default.createElement("div", null, /* @__PURE__ */ React__default.createElement("label", { htmlFor: "link-url" }, "URL")), /* @__PURE__ */ React__default.createElement("div", { className: styles.linkDialogInputContainer }, /* @__PURE__ */ React__default.createElement("div", { "data-visible-dropdown": dropdownIsVisible, className: styles.linkDialogInputWrapper }, /* @__PURE__ */ React__default.createElement("input", { id: "link-url", className: styles.linkDialogInput, ...inputProps, autoFocus: true, size: 40, "data-editor-dialog": true }), /* @__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.linkDialogAutocompleteContainer }, /* @__PURE__ */ React__default.createElement("ul", { ...getMenuProps(), "data-visible": dropdownIsVisible }, items.map((item, index) => /* @__PURE__ */ React__default.createElement(
70
- "li",
30
+ return /* @__PURE__ */ React__default.createElement(
31
+ "form",
71
32
  {
72
- "data-selected": selectedItem === item,
73
- "data-highlighted": highlightedIndex === index,
74
- key: `${item}${index}`,
75
- ...getItemProps({ item, index })
33
+ onSubmit: (e) => {
34
+ void handleSubmit(onSubmit)(e);
35
+ e.nativeEvent.stopImmediatePropagation();
36
+ },
37
+ onReset: onCancel,
38
+ className: classNames(styles.multiFieldForm, styles.linkDialogEditForm)
76
39
  },
77
- item
78
- ))))), /* @__PURE__ */ React__default.createElement("div", null, /* @__PURE__ */ React__default.createElement("label", { htmlFor: "link-title" }, "Title")), /* @__PURE__ */ React__default.createElement("div", null, /* @__PURE__ */ React__default.createElement("div", { className: styles.linkDialogInputWrapper }, /* @__PURE__ */ React__default.createElement("input", { id: "link-title", className: styles.linkDialogInput, size: 40, value: title, onChange: (e) => setTitle(e.target.value) }))), /* @__PURE__ */ React__default.createElement("div", { style: { display: "flex", justifyContent: "flex-end", gap: "var(--spacing-2)" } }, /* @__PURE__ */ React__default.createElement("button", { type: "reset", title: "Cancel change", "aria-label": "Cancel change", className: classNames(styles.secondaryButton) }, "Cancel"), /* @__PURE__ */ React__default.createElement("button", { type: "submit", title: "Set URL", "aria-label": "Set URL", className: classNames(styles.primaryButton), onClick: handleSaveClick }, "Save")));
40
+ /* @__PURE__ */ React__default.createElement("div", { className: styles.formField }, /* @__PURE__ */ React__default.createElement("label", { htmlFor: "link-url" }, "URL"), /* @__PURE__ */ React__default.createElement(
41
+ DownshiftAutoComplete,
42
+ {
43
+ initialInputValue: url,
44
+ inputName: "url",
45
+ suggestions: linkAutocompleteSuggestions,
46
+ setValue,
47
+ control,
48
+ placeholder: "Select or paste an URL",
49
+ autofocus: true
50
+ }
51
+ )),
52
+ /* @__PURE__ */ React__default.createElement("div", { className: styles.formField }, /* @__PURE__ */ React__default.createElement("label", { htmlFor: "link-title" }, "Title"), /* @__PURE__ */ React__default.createElement("input", { id: "link-title", className: styles.textInput, size: 40, ...register("title") })),
53
+ /* @__PURE__ */ React__default.createElement("div", { style: { display: "flex", justifyContent: "flex-end", gap: "var(--spacing-2)" } }, /* @__PURE__ */ React__default.createElement("button", { type: "submit", title: "Set URL", "aria-label": "Set URL", className: classNames(styles.primaryButton) }, "Save"), /* @__PURE__ */ React__default.createElement("button", { type: "reset", title: "Cancel change", "aria-label": "Cancel change", className: classNames(styles.secondaryButton) }, "Cancel"))
54
+ );
79
55
  }
80
56
  const LinkDialog = () => {
81
57
  const [editorRootElementRef] = corePluginHooks.useEmitterValues("editorRootElementRef");
@@ -85,11 +61,10 @@ const LinkDialog = () => {
85
61
  "linkDialogState",
86
62
  "linkAutocompleteSuggestions"
87
63
  );
88
- const updateLinkUrl = linkDialogPluginHooks.usePublisher("updateLinkUrl");
64
+ const updateLink = linkDialogPluginHooks.usePublisher("updateLink");
89
65
  const cancelLinkEdit = linkDialogPluginHooks.usePublisher("cancelLinkEdit");
90
66
  const switchFromPreviewToLinkEdit = linkDialogPluginHooks.usePublisher("switchFromPreviewToLinkEdit");
91
67
  const removeLink = linkDialogPluginHooks.usePublisher("removeLink");
92
- const applyLinkChanges = linkDialogPluginHooks.usePublisher("applyLinkChanges");
93
68
  React__default.useEffect(() => {
94
69
  const update = () => {
95
70
  activeEditor == null ? void 0 : activeEditor.getEditorState().read(() => {
@@ -105,13 +80,6 @@ const LinkDialog = () => {
105
80
  }, [activeEditor, publishWindowChange]);
106
81
  const [copyUrlTooltipOpen, setCopyUrlTooltipOpen] = React__default.useState(false);
107
82
  const theRect = linkDialogState == null ? void 0 : linkDialogState.rectangle;
108
- const onSubmitEH = React__default.useCallback(
109
- (payload) => {
110
- updateLinkUrl(payload);
111
- applyLinkChanges(true);
112
- },
113
- [applyLinkChanges, updateLinkUrl]
114
- );
115
83
  const urlIsExternal = linkDialogState.type === "preview" && linkDialogState.url.startsWith("http");
116
84
  return /* @__PURE__ */ React__default.createElement(RadixPopover.Root, { open: linkDialogState.type !== "inactive" }, /* @__PURE__ */ React__default.createElement(
117
85
  RadixPopover.Anchor,
@@ -136,9 +104,9 @@ const LinkDialog = () => {
136
104
  linkDialogState.type === "edit" && /* @__PURE__ */ React__default.createElement(
137
105
  LinkEditForm,
138
106
  {
139
- initialUrl: linkDialogState.url,
140
- initialTitle: linkDialogState.title,
141
- onSubmit: onSubmitEH,
107
+ url: linkDialogState.url,
108
+ title: linkDialogState.title,
109
+ onSubmit: updateLink,
142
110
  onCancel: cancelLinkEdit.bind(null, true),
143
111
  linkAutocompleteSuggestions
144
112
  }
@@ -148,7 +148,10 @@ linkDialogPlugin: PluginConstructor<SystemSpec<[SystemSpec<[], (r: Realm) => {
148
148
  dialogState: RealmNode<boolean>;
149
149
  onWindowChange: RealmNode<true>;
150
150
  linkDialogState: RealmNode<InactiveLinkDialog | PreviewLinkDialog | EditLinkDialog>;
151
- updateLinkUrl: RealmNode<[string, string]>;
151
+ updateLink: RealmNode<{
152
+ url: string;
153
+ title: string;
154
+ }>;
152
155
  switchFromPreviewToLinkEdit: RealmNode<true>;
153
156
  cancelLinkEdit: RealmNode<true>;
154
157
  removeLink: RealmNode<true>;
@@ -164,7 +167,10 @@ linkDialogPluginHooks: {
164
167
  dialogState: RealmNode<boolean>;
165
168
  onWindowChange: RealmNode<true>;
166
169
  linkDialogState: RealmNode<InactiveLinkDialog | PreviewLinkDialog | EditLinkDialog>;
167
- updateLinkUrl: RealmNode<[string, string]>;
170
+ updateLink: RealmNode<{
171
+ url: string;
172
+ title: string;
173
+ }>;
168
174
  switchFromPreviewToLinkEdit: RealmNode<true>;
169
175
  cancelLinkEdit: RealmNode<true>;
170
176
  removeLink: RealmNode<true>;
@@ -227,11 +233,14 @@ linkDialogPluginHooks: {
227
233
  insertDecoratorNode: RealmNode<() => DecoratorNode<unknown>>;
228
234
  onBlur: RealmNode<FocusEvent>;
229
235
  }>;
230
- 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" | "dialogState" | "onWindowChange" | "linkDialogState" | "updateLinkUrl" | "switchFromPreviewToLinkEdit" | "cancelLinkEdit" | "removeLink" | "openLinkEditDialog" | "applyLinkChanges" | "linkAutocompleteSuggestions">(key: K, callback: (value: ValueForKey<{
236
+ 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" | "dialogState" | "onWindowChange" | "linkDialogState" | "updateLink" | "switchFromPreviewToLinkEdit" | "cancelLinkEdit" | "removeLink" | "openLinkEditDialog" | "applyLinkChanges" | "linkAutocompleteSuggestions">(key: K, callback: (value: ValueForKey<{
231
237
  dialogState: RealmNode<boolean>;
232
238
  onWindowChange: RealmNode<true>;
233
239
  linkDialogState: RealmNode<InactiveLinkDialog | PreviewLinkDialog | EditLinkDialog>;
234
- updateLinkUrl: RealmNode<[string, string]>;
240
+ updateLink: RealmNode<{
241
+ url: string;
242
+ title: string;
243
+ }>;
235
244
  switchFromPreviewToLinkEdit: RealmNode<true>;
236
245
  cancelLinkEdit: RealmNode<true>;
237
246
  removeLink: RealmNode<true>;
@@ -298,7 +307,10 @@ linkDialogPluginHooks: {
298
307
  dialogState: RealmNode<boolean>;
299
308
  onWindowChange: RealmNode<true>;
300
309
  linkDialogState: RealmNode<InactiveLinkDialog | PreviewLinkDialog | EditLinkDialog>;
301
- updateLinkUrl: RealmNode<[string, string]>;
310
+ updateLink: RealmNode<{
311
+ url: string;
312
+ title: string;
313
+ }>;
302
314
  switchFromPreviewToLinkEdit: RealmNode<true>;
303
315
  cancelLinkEdit: RealmNode<true>;
304
316
  removeLink: RealmNode<true>;
@@ -364,7 +376,10 @@ linkDialogPluginHooks: {
364
376
  dialogState: RealmNode<boolean>;
365
377
  onWindowChange: RealmNode<true>;
366
378
  linkDialogState: RealmNode<InactiveLinkDialog | PreviewLinkDialog | EditLinkDialog>;
367
- updateLinkUrl: RealmNode<[string, string]>;
379
+ updateLink: RealmNode<{
380
+ url: string;
381
+ title: string;
382
+ }>;
368
383
  switchFromPreviewToLinkEdit: RealmNode<true>;
369
384
  cancelLinkEdit: RealmNode<true>;
370
385
  removeLink: RealmNode<true>;
@@ -431,7 +446,10 @@ linkDialogPluginHooks: {
431
446
  dialogState: RealmNode<boolean>;
432
447
  onWindowChange: RealmNode<true>;
433
448
  linkDialogState: RealmNode<InactiveLinkDialog | PreviewLinkDialog | EditLinkDialog>;
434
- updateLinkUrl: RealmNode<[string, string]>;
449
+ updateLink: RealmNode<{
450
+ url: string;
451
+ title: string;
452
+ }>;
435
453
  switchFromPreviewToLinkEdit: RealmNode<true>;
436
454
  cancelLinkEdit: RealmNode<true>;
437
455
  removeLink: RealmNode<true>;
@@ -494,11 +512,14 @@ linkDialogPluginHooks: {
494
512
  insertDecoratorNode: RealmNode<() => DecoratorNode<unknown>>;
495
513
  onBlur: RealmNode<FocusEvent>;
496
514
  }>) => void;
497
- 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" | "dialogState" | "onWindowChange" | "linkDialogState" | "updateLinkUrl" | "switchFromPreviewToLinkEdit" | "cancelLinkEdit" | "removeLink" | "openLinkEditDialog" | "applyLinkChanges" | "linkAutocompleteSuggestions">(key: K_2) => (value: ValueForKey<{
515
+ 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" | "dialogState" | "onWindowChange" | "linkDialogState" | "updateLink" | "switchFromPreviewToLinkEdit" | "cancelLinkEdit" | "removeLink" | "openLinkEditDialog" | "applyLinkChanges" | "linkAutocompleteSuggestions">(key: K_2) => (value: ValueForKey<{
498
516
  dialogState: RealmNode<boolean>;
499
517
  onWindowChange: RealmNode<true>;
500
518
  linkDialogState: RealmNode<InactiveLinkDialog | PreviewLinkDialog | EditLinkDialog>;
501
- updateLinkUrl: RealmNode<[string, string]>;
519
+ updateLink: RealmNode<{
520
+ url: string;
521
+ title: string;
522
+ }>;
502
523
  switchFromPreviewToLinkEdit: RealmNode<true>;
503
524
  cancelLinkEdit: RealmNode<true>;
504
525
  removeLink: RealmNode<true>;
@@ -27,7 +27,7 @@ const linkDialogSystem = system(
27
27
  const dialogState = r.node(false);
28
28
  const onWindowChange = r.node();
29
29
  const linkDialogState = r.node({ type: "inactive" }, true);
30
- const updateLinkUrl = r.node();
30
+ const updateLink = r.node();
31
31
  const cancelLinkEdit = r.node();
32
32
  const applyLinkChanges = r.node();
33
33
  const switchFromPreviewToLinkEdit = r.node();
@@ -124,54 +124,32 @@ const linkDialogSystem = system(
124
124
  ),
125
125
  linkDialogState
126
126
  );
127
- r.sub(r.pipe(applyLinkChanges, r.o.withLatestFrom(linkDialogState, activeEditor)), ([, state, editor]) => {
128
- if (state.type === "edit") {
129
- const url = state.url.trim();
130
- const title = state.title.trim();
131
- if (url.trim() !== "") {
132
- editor == null ? void 0 : editor.dispatchCommand(TOGGLE_LINK_COMMAND, { url, title });
133
- setTimeout(() => {
134
- editor == null ? void 0 : editor.update(() => {
135
- const node = getLinkNodeInSelection($getSelection());
136
- node == null ? void 0 : node.setTitle(title);
137
- });
138
- });
139
- r.pub(linkDialogState, {
140
- type: "preview",
141
- linkNodeKey: state.linkNodeKey,
142
- rectangle: state.rectangle,
143
- url
144
- });
145
- } else {
146
- if (state.initialUrl !== "") {
147
- editor == null ? void 0 : editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
148
- }
149
- r.pub(linkDialogState, {
150
- type: "inactive"
127
+ r.sub(r.pipe(updateLink, r.o.withLatestFrom(activeEditor, linkDialogState)), ([payload, editor, state]) => {
128
+ const url = payload.url.trim();
129
+ const title = payload.title.trim();
130
+ if (url.trim() !== "") {
131
+ editor == null ? void 0 : editor.dispatchCommand(TOGGLE_LINK_COMMAND, { url, title });
132
+ setTimeout(() => {
133
+ editor == null ? void 0 : editor.update(() => {
134
+ const node = getLinkNodeInSelection($getSelection());
135
+ node == null ? void 0 : node.setTitle(title);
151
136
  });
152
- }
137
+ });
138
+ r.pub(linkDialogState, {
139
+ type: "preview",
140
+ linkNodeKey: state.linkNodeKey,
141
+ rectangle: state.rectangle,
142
+ url
143
+ });
153
144
  } else {
154
- throw new Error("Cannot apply link edit when not in edit mode");
145
+ if (state.type === "edit" && state.initialUrl !== "") {
146
+ editor == null ? void 0 : editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
147
+ }
148
+ r.pub(linkDialogState, {
149
+ type: "inactive"
150
+ });
155
151
  }
156
152
  });
157
- r.link(
158
- r.pipe(
159
- updateLinkUrl,
160
- r.o.withLatestFrom(linkDialogState),
161
- r.o.map(([[url, title], state]) => {
162
- if (state.type === "edit") {
163
- return {
164
- ...state,
165
- url,
166
- title
167
- };
168
- } else {
169
- throw new Error("Cannot update link url when not in edit mode");
170
- }
171
- })
172
- ),
173
- linkDialogState
174
- );
175
153
  r.link(
176
154
  r.pipe(
177
155
  cancelLinkEdit,
@@ -230,7 +208,7 @@ const linkDialogSystem = system(
230
208
  dialogState,
231
209
  onWindowChange,
232
210
  linkDialogState,
233
- updateLinkUrl,
211
+ updateLink,
234
212
  switchFromPreviewToLinkEdit,
235
213
  cancelLinkEdit,
236
214
  removeLink,
@@ -1,22 +1,14 @@
1
1
  import React__default from "react";
2
2
  import { imagePluginHooks } from "../../image/index.js";
3
- import { DialogButton } from "../primitives/DialogButton.js";
3
+ import * as RadixToolbar from "@radix-ui/react-toolbar";
4
4
  import AddPhotoIcon from "../../../icons/add_photo.svg.js";
5
+ import styles from "../../../styles/ui.module.css.js";
6
+ import { corePluginHooks } from "../../core/index.js";
7
+ import { TooltipWrap } from "../primitives/TooltipWrap.js";
5
8
  const InsertImage = React__default.forwardRef((_, forwardedRef) => {
6
- const [imageAutocompleteSuggestions] = imagePluginHooks.useEmitterValues("imageAutocompleteSuggestions");
7
- const insertImage = imagePluginHooks.usePublisher("insertImage");
8
- return /* @__PURE__ */ React__default.createElement(
9
- DialogButton,
10
- {
11
- ref: forwardedRef,
12
- submitButtonTitle: "Insert Image",
13
- dialogInputPlaceholder: "Paste or select image URL",
14
- tooltipTitle: "Insert image",
15
- onSubmit: insertImage,
16
- buttonContent: /* @__PURE__ */ React__default.createElement(AddPhotoIcon, null),
17
- autocompleteSuggestions: imageAutocompleteSuggestions
18
- }
19
- );
9
+ const openNewImageDialog = imagePluginHooks.usePublisher("openNewImageDialog");
10
+ const [readOnly] = corePluginHooks.useEmitterValues("readOnly");
11
+ return /* @__PURE__ */ React__default.createElement(RadixToolbar.Button, { className: styles.toolbarButton, ref: forwardedRef, disabled: readOnly, onClick: () => openNewImageDialog(true) }, /* @__PURE__ */ React__default.createElement(TooltipWrap, { title: "Insert image" }, /* @__PURE__ */ React__default.createElement(AddPhotoIcon, null)));
20
12
  });
21
13
  export {
22
14
  InsertImage
@@ -77,7 +77,7 @@ const DialogForm = ({ autocompleteSuggestions, onSubmitCallback, dialogInputPlac
77
77
  };
78
78
  const onSubmitEH = (e) => {
79
79
  e.preventDefault();
80
- e.stopPropagation();
80
+ e.nativeEvent.stopImmediatePropagation();
81
81
  onSubmitCallback(inputProps.value);
82
82
  };
83
83
  const dropdownIsVisible = isOpen && items.length > 0;
@@ -91,7 +91,7 @@ const DialogForm = ({ autocompleteSuggestions, onSubmitCallback, dialogInputPlac
91
91
  size: 30,
92
92
  "data-editor-dialog": true
93
93
  }
94
- ), 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.linkDialogAutocompleteContainer }, /* @__PURE__ */ React__default.createElement("ul", { ...getMenuProps(), "data-visible": dropdownIsVisible }, items.map((item, index) => /* @__PURE__ */ React__default.createElement(
94
+ ), 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(
95
95
  "li",
96
96
  {
97
97
  "data-selected": selectedItem === item,