@gravity-ui/markdown-editor 14.0.2 → 14.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.
Files changed (103) hide show
  1. package/build/cjs/bundle/Editor.d.ts +1 -1
  2. package/build/cjs/bundle/Editor.js +19 -7
  3. package/build/cjs/bundle/config/action-names.d.ts +1 -1
  4. package/build/cjs/bundle/toolbar/markup/MToolbarImagePopup.d.ts +1 -1
  5. package/build/cjs/bundle/toolbar/markup/MToolbarImagePopup.js +4 -5
  6. package/build/cjs/bundle/types.d.ts +16 -2
  7. package/build/cjs/bundle/useMarkdownEditor.js +5 -2
  8. package/build/cjs/bundle/wysiwyg-preset.d.ts +1 -0
  9. package/build/cjs/bundle/wysiwyg-preset.js +6 -4
  10. package/build/cjs/core/markdown/MarkdownSerializer.js +1 -1
  11. package/build/cjs/extensions/additional/Mermaid/MermaidNodeView/MermaidView.js +2 -2
  12. package/build/cjs/extensions/markdown/CodeBlock/CodeBlockHighlight/CodeBlockHighlight.js +1 -4
  13. package/build/cjs/extensions/markdown/Image/ImageSpecs/index.js +13 -6
  14. package/build/cjs/extensions/markdown/Image/imageUrlPaste/index.d.ts +9 -0
  15. package/build/cjs/extensions/markdown/Image/imageUrlPaste/index.js +34 -0
  16. package/build/cjs/extensions/markdown/Image/index.d.ts +3 -1
  17. package/build/cjs/extensions/markdown/Image/index.js +8 -1
  18. package/build/cjs/extensions/markdown/Lists/inputrules.d.ts +1 -1
  19. package/build/cjs/extensions/markdown/Lists/inputrules.js +5 -2
  20. package/build/cjs/extensions/yfm/Emoji/EmojiSuggest/EmojiSuggestComponent.js +2 -3
  21. package/build/cjs/extensions/yfm/ImgSize/ImagePaste/index.d.ts +8 -3
  22. package/build/cjs/extensions/yfm/ImgSize/ImagePaste/index.js +31 -8
  23. package/build/cjs/extensions/yfm/ImgSize/ImagePaste/upload.d.ts +2 -1
  24. package/build/cjs/extensions/yfm/ImgSize/ImagePaste/upload.js +17 -7
  25. package/build/cjs/extensions/yfm/ImgSize/ImageWidget/widget.js +1 -1
  26. package/build/cjs/extensions/yfm/ImgSize/ImgSizeSpecs/index.js +15 -8
  27. package/build/cjs/extensions/yfm/ImgSize/index.d.ts +2 -3
  28. package/build/cjs/extensions/yfm/ImgSize/index.js +4 -2
  29. package/build/cjs/extensions/yfm/ImgSize/plugins/ImgSizeNodeView/NodeView.js +10 -2
  30. package/build/cjs/extensions/yfm/ImgSize/utils.d.ts +6 -2
  31. package/build/cjs/extensions/yfm/ImgSize/utils.js +13 -3
  32. package/build/cjs/extensions/yfm/Video/VideoSpecs/index.js +1 -1
  33. package/build/cjs/extensions/yfm/YfmFile/YfmFilePaste/index.d.ts +1 -1
  34. package/build/cjs/extensions/yfm/YfmFile/YfmFilePaste/index.js +1 -1
  35. package/build/cjs/i18n/menubar/index.d.ts +1 -1
  36. package/build/cjs/i18n/placeholder/index.d.ts +1 -1
  37. package/build/cjs/i18n/yfm-note/index.d.ts +1 -1
  38. package/build/cjs/markup/codemirror/create.d.ts +4 -1
  39. package/build/cjs/markup/codemirror/create.js +21 -2
  40. package/build/cjs/markup/codemirror/files-upload-facet.d.ts +4 -2
  41. package/build/cjs/markup/codemirror/files-upload-plugin/plugin.js +30 -19
  42. package/build/cjs/markup/codemirror/files-upload-plugin/utils.js +4 -4
  43. package/build/cjs/markup/codemirror/yfm.d.ts +1 -1
  44. package/build/cjs/markup/commands/inline.js +9 -3
  45. package/build/cjs/presets/commonmark.d.ts +2 -2
  46. package/build/cjs/presets/commonmark.js +1 -1
  47. package/build/cjs/utils/get-proportional-size.d.ts +10 -0
  48. package/build/cjs/utils/get-proportional-size.js +14 -0
  49. package/build/cjs/utils/index.d.ts +2 -1
  50. package/build/cjs/utils/index.js +2 -7
  51. package/build/cjs/version.js +1 -1
  52. package/build/esm/bundle/Editor.d.ts +1 -1
  53. package/build/esm/bundle/Editor.js +17 -5
  54. package/build/esm/bundle/config/action-names.d.ts +1 -1
  55. package/build/esm/bundle/toolbar/markup/MToolbarImagePopup.d.ts +1 -1
  56. package/build/esm/bundle/toolbar/markup/MToolbarImagePopup.js +3 -4
  57. package/build/esm/bundle/types.d.ts +16 -2
  58. package/build/esm/bundle/useMarkdownEditor.js +5 -2
  59. package/build/esm/bundle/wysiwyg-preset.d.ts +1 -0
  60. package/build/esm/bundle/wysiwyg-preset.js +6 -4
  61. package/build/esm/core/markdown/MarkdownSerializer.js +1 -1
  62. package/build/esm/extensions/additional/Mermaid/MermaidNodeView/MermaidView.js +2 -2
  63. package/build/esm/extensions/markdown/CodeBlock/CodeBlockHighlight/CodeBlockHighlight.js +1 -4
  64. package/build/esm/extensions/markdown/Image/ImageSpecs/index.js +13 -6
  65. package/build/esm/extensions/markdown/Image/imageUrlPaste/index.d.ts +9 -0
  66. package/build/esm/extensions/markdown/Image/imageUrlPaste/index.js +30 -0
  67. package/build/esm/extensions/markdown/Image/index.d.ts +3 -1
  68. package/build/esm/extensions/markdown/Image/index.js +8 -1
  69. package/build/esm/extensions/markdown/Lists/inputrules.d.ts +1 -1
  70. package/build/esm/extensions/markdown/Lists/inputrules.js +5 -2
  71. package/build/esm/extensions/yfm/Emoji/EmojiSuggest/EmojiSuggestComponent.js +2 -3
  72. package/build/esm/extensions/yfm/ImgSize/ImagePaste/index.d.ts +8 -3
  73. package/build/esm/extensions/yfm/ImgSize/ImagePaste/index.js +29 -6
  74. package/build/esm/extensions/yfm/ImgSize/ImagePaste/upload.d.ts +2 -1
  75. package/build/esm/extensions/yfm/ImgSize/ImagePaste/upload.js +15 -5
  76. package/build/esm/extensions/yfm/ImgSize/ImageWidget/widget.js +1 -1
  77. package/build/esm/extensions/yfm/ImgSize/ImgSizeSpecs/index.js +15 -8
  78. package/build/esm/extensions/yfm/ImgSize/index.d.ts +2 -3
  79. package/build/esm/extensions/yfm/ImgSize/index.js +4 -2
  80. package/build/esm/extensions/yfm/ImgSize/plugins/ImgSizeNodeView/NodeView.js +10 -2
  81. package/build/esm/extensions/yfm/ImgSize/utils.d.ts +6 -2
  82. package/build/esm/extensions/yfm/ImgSize/utils.js +11 -2
  83. package/build/esm/extensions/yfm/Video/VideoSpecs/index.js +1 -1
  84. package/build/esm/extensions/yfm/YfmFile/YfmFilePaste/index.d.ts +1 -1
  85. package/build/esm/extensions/yfm/YfmFile/YfmFilePaste/index.js +1 -1
  86. package/build/esm/i18n/menubar/index.d.ts +1 -1
  87. package/build/esm/i18n/placeholder/index.d.ts +1 -1
  88. package/build/esm/i18n/yfm-note/index.d.ts +1 -1
  89. package/build/esm/markup/codemirror/create.d.ts +4 -1
  90. package/build/esm/markup/codemirror/create.js +22 -3
  91. package/build/esm/markup/codemirror/files-upload-facet.d.ts +4 -2
  92. package/build/esm/markup/codemirror/files-upload-plugin/plugin.js +22 -11
  93. package/build/esm/markup/codemirror/files-upload-plugin/utils.js +1 -1
  94. package/build/esm/markup/codemirror/yfm.d.ts +1 -1
  95. package/build/esm/markup/commands/inline.js +9 -3
  96. package/build/esm/presets/commonmark.d.ts +2 -2
  97. package/build/esm/presets/commonmark.js +1 -1
  98. package/build/esm/utils/get-proportional-size.d.ts +10 -0
  99. package/build/esm/utils/get-proportional-size.js +10 -0
  100. package/build/esm/utils/index.d.ts +2 -1
  101. package/build/esm/utils/index.js +2 -1
  102. package/build/esm/version.js +1 -1
  103. package/package.json +10 -7
@@ -2,4 +2,4 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
4
  /** During build process, the current version will be injected here */
5
- exports.VERSION = typeof '14.0.2' !== 'undefined' ? '14.0.2' : 'unknown';
5
+ exports.VERSION = typeof '14.2.0' !== 'undefined' ? '14.2.0' : 'unknown';
@@ -1,6 +1,6 @@
1
1
  import type { CommonEditor } from '../common';
2
2
  import { ReactRenderStorage } from '../extensions';
3
- import { type Receiver } from '../utils/event-emitter';
3
+ import { type Receiver } from '../utils';
4
4
  import type { MarkdownEditorMode as EditorMode, MarkdownEditorPreset as EditorPreset, MarkdownEditorOptions } from './types';
5
5
  export declare type ToolbarActionData = {
6
6
  editorMode: EditorMode;
@@ -1,13 +1,13 @@
1
- var _EditorImpl_markup, _EditorImpl_editorMode, _EditorImpl_toolbarVisible, _EditorImpl_splitModeEnabled, _EditorImpl_splitMode, _EditorImpl_renderPreview, _EditorImpl_wysiwygEditor, _EditorImpl_markupEditor, _EditorImpl_markupConfig, _EditorImpl_escapeConfig, _EditorImpl_mdOptions, _EditorImpl_preset, _EditorImpl_extensions, _EditorImpl_renderStorage, _EditorImpl_fileUploadHandler, _EditorImpl_needToSetDimensionsForUploadedImages, _EditorImpl_prepareRawMarkup, _EditorImpl_beforeEditorModeChange;
1
+ var _EditorImpl_markup, _EditorImpl_editorMode, _EditorImpl_toolbarVisible, _EditorImpl_splitModeEnabled, _EditorImpl_splitMode, _EditorImpl_renderPreview, _EditorImpl_wysiwygEditor, _EditorImpl_markupEditor, _EditorImpl_markupConfig, _EditorImpl_escapeConfig, _EditorImpl_mdOptions, _EditorImpl_preset, _EditorImpl_extensions, _EditorImpl_renderStorage, _EditorImpl_fileUploadHandler, _EditorImpl_parseInsertedUrlAsImage, _EditorImpl_needToSetDimensionsForUploadedImages, _EditorImpl_enableNewImageSizeCalculation, _EditorImpl_prepareRawMarkup, _EditorImpl_beforeEditorModeChange;
2
2
  import { __classPrivateFieldGet, __classPrivateFieldSet, __rest } from "tslib";
3
3
  import { EditorView as CMEditorView } from '@codemirror/view';
4
4
  import { TextSelection } from 'prosemirror-state';
5
5
  import { WysiwygEditor, } from '../core';
6
6
  import { i18n } from '../i18n/bundle';
7
7
  import { logger } from '../logger';
8
- import { createCodemirror } from '../markup/codemirror';
8
+ import { createCodemirror } from '../markup';
9
9
  import { Editor as MarkupEditor } from '../markup/editor';
10
- import { SafeEventEmitter } from '../utils/event-emitter';
10
+ import { SafeEventEmitter } from '../utils';
11
11
  /** @internal */
12
12
  export class EditorImpl extends SafeEventEmitter {
13
13
  constructor(opts) {
@@ -28,7 +28,9 @@ export class EditorImpl extends SafeEventEmitter {
28
28
  _EditorImpl_extensions.set(this, void 0);
29
29
  _EditorImpl_renderStorage.set(this, void 0);
30
30
  _EditorImpl_fileUploadHandler.set(this, void 0);
31
+ _EditorImpl_parseInsertedUrlAsImage.set(this, void 0);
31
32
  _EditorImpl_needToSetDimensionsForUploadedImages.set(this, void 0);
33
+ _EditorImpl_enableNewImageSizeCalculation.set(this, void 0);
32
34
  _EditorImpl_prepareRawMarkup.set(this, void 0);
33
35
  _EditorImpl_beforeEditorModeChange.set(this, void 0);
34
36
  this.getValue = () => this.currentEditor.getValue();
@@ -45,7 +47,9 @@ export class EditorImpl extends SafeEventEmitter {
45
47
  __classPrivateFieldSet(this, _EditorImpl_markupConfig, Object.assign({}, opts.markupConfig), "f");
46
48
  __classPrivateFieldSet(this, _EditorImpl_renderStorage, opts.renderStorage, "f");
47
49
  __classPrivateFieldSet(this, _EditorImpl_fileUploadHandler, handlers.uploadFile, "f");
50
+ __classPrivateFieldSet(this, _EditorImpl_parseInsertedUrlAsImage, markupConfig.parseInsertedUrlAsImage, "f");
48
51
  __classPrivateFieldSet(this, _EditorImpl_needToSetDimensionsForUploadedImages, Boolean(experimental.needToSetDimensionsForUploadedImages), "f");
52
+ __classPrivateFieldSet(this, _EditorImpl_enableNewImageSizeCalculation, Boolean(experimental.enableNewImageSizeCalculation), "f");
49
53
  __classPrivateFieldSet(this, _EditorImpl_prepareRawMarkup, experimental.prepareRawMarkup, "f");
50
54
  __classPrivateFieldSet(this, _EditorImpl_escapeConfig, wysiwygConfig.escapeConfig, "f");
51
55
  __classPrivateFieldSet(this, _EditorImpl_beforeEditorModeChange, experimental.beforeEditorModeChange, "f");
@@ -157,7 +161,9 @@ export class EditorImpl extends SafeEventEmitter {
157
161
  onScroll: (event) => this.emit('cm-scroll', { event }),
158
162
  reactRenderer: __classPrivateFieldGet(this, _EditorImpl_renderStorage, "f"),
159
163
  uploadHandler: this.fileUploadHandler,
160
- needImgDimms: this.needToSetDimensionsForUploadedImages,
164
+ parseInsertedUrlAsImage: this.parseInsertedUrlAsImage,
165
+ needImageDimensions: this.needToSetDimensionsForUploadedImages,
166
+ enableNewImageSizeCalculation: this.enableNewImageSizeCalculation,
161
167
  extensions: __classPrivateFieldGet(this, _EditorImpl_markupConfig, "f").extensions,
162
168
  disabledExtensions: __classPrivateFieldGet(this, _EditorImpl_markupConfig, "f").disabledExtensions,
163
169
  keymaps: __classPrivateFieldGet(this, _EditorImpl_markupConfig, "f").keymaps,
@@ -174,9 +180,15 @@ export class EditorImpl extends SafeEventEmitter {
174
180
  get fileUploadHandler() {
175
181
  return __classPrivateFieldGet(this, _EditorImpl_fileUploadHandler, "f");
176
182
  }
183
+ get parseInsertedUrlAsImage() {
184
+ return __classPrivateFieldGet(this, _EditorImpl_parseInsertedUrlAsImage, "f");
185
+ }
177
186
  get needToSetDimensionsForUploadedImages() {
178
187
  return __classPrivateFieldGet(this, _EditorImpl_needToSetDimensionsForUploadedImages, "f");
179
188
  }
189
+ get enableNewImageSizeCalculation() {
190
+ return __classPrivateFieldGet(this, _EditorImpl_enableNewImageSizeCalculation, "f");
191
+ }
180
192
  // ---> implements CodeEditor
181
193
  get cm() {
182
194
  return this.markupEditor.cm;
@@ -296,7 +308,7 @@ export class EditorImpl extends SafeEventEmitter {
296
308
  return (serializedEditorMarkup === null || serializedEditorMarkup === void 0 ? void 0 : serializedEditorMarkup.trim()) !== wysiwygValue.trim();
297
309
  }
298
310
  }
299
- _EditorImpl_markup = new WeakMap(), _EditorImpl_editorMode = new WeakMap(), _EditorImpl_toolbarVisible = new WeakMap(), _EditorImpl_splitModeEnabled = new WeakMap(), _EditorImpl_splitMode = new WeakMap(), _EditorImpl_renderPreview = new WeakMap(), _EditorImpl_wysiwygEditor = new WeakMap(), _EditorImpl_markupEditor = new WeakMap(), _EditorImpl_markupConfig = new WeakMap(), _EditorImpl_escapeConfig = new WeakMap(), _EditorImpl_mdOptions = new WeakMap(), _EditorImpl_preset = new WeakMap(), _EditorImpl_extensions = new WeakMap(), _EditorImpl_renderStorage = new WeakMap(), _EditorImpl_fileUploadHandler = new WeakMap(), _EditorImpl_needToSetDimensionsForUploadedImages = new WeakMap(), _EditorImpl_prepareRawMarkup = new WeakMap(), _EditorImpl_beforeEditorModeChange = new WeakMap();
311
+ _EditorImpl_markup = new WeakMap(), _EditorImpl_editorMode = new WeakMap(), _EditorImpl_toolbarVisible = new WeakMap(), _EditorImpl_splitModeEnabled = new WeakMap(), _EditorImpl_splitMode = new WeakMap(), _EditorImpl_renderPreview = new WeakMap(), _EditorImpl_wysiwygEditor = new WeakMap(), _EditorImpl_markupEditor = new WeakMap(), _EditorImpl_markupConfig = new WeakMap(), _EditorImpl_escapeConfig = new WeakMap(), _EditorImpl_mdOptions = new WeakMap(), _EditorImpl_preset = new WeakMap(), _EditorImpl_extensions = new WeakMap(), _EditorImpl_renderStorage = new WeakMap(), _EditorImpl_fileUploadHandler = new WeakMap(), _EditorImpl_parseInsertedUrlAsImage = new WeakMap(), _EditorImpl_needToSetDimensionsForUploadedImages = new WeakMap(), _EditorImpl_enableNewImageSizeCalculation = new WeakMap(), _EditorImpl_prepareRawMarkup = new WeakMap(), _EditorImpl_beforeEditorModeChange = new WeakMap();
300
312
  function getTopOffset(elem) {
301
313
  const TOOLBAR_HEIGHT = 36; //px
302
314
  const TOOLBAR_BOTTOM_OFFSET = 8; // px
@@ -1,3 +1,3 @@
1
- declare const namesObj: Record<"bold" | "link" | "italic" | "strike" | "underline" | "mark" | "quote" | "mono" | "paragraph" | "anchor" | "table" | "image" | "code_inline" | "code_block" | "file" | "checkbox" | "bulletList" | "orderedList" | "emoji" | "tabs" | "yfm_cut" | "heading1" | "heading2" | "heading3" | "heading4" | "heading5" | "heading6" | "yfm_note" | "gpt" | "undo" | "redo" | "liftListItem" | "sinkListItem" | "yfm_block" | "yfm_html_block" | "yfm_layout" | "horizontalrule" | "math_inline" | "math_block" | "mermaid", string>;
1
+ declare const namesObj: Record<"bold" | "mono" | "link" | "italic" | "strike" | "underline" | "mark" | "quote" | "paragraph" | "anchor" | "table" | "image" | "code_inline" | "code_block" | "file" | "checkbox" | "emoji" | "undo" | "redo" | "heading1" | "heading2" | "heading3" | "heading4" | "heading5" | "heading6" | "bulletList" | "orderedList" | "liftListItem" | "sinkListItem" | "yfm_cut" | "yfm_note" | "yfm_block" | "yfm_html_block" | "yfm_layout" | "horizontalrule" | "math_inline" | "math_block" | "tabs" | "mermaid" | "gpt", string>;
2
2
  export declare const ActionName: Readonly<typeof namesObj>;
3
3
  export {};
@@ -1,5 +1,5 @@
1
1
  import React, { RefObject } from 'react';
2
- import type { CodeEditor } from '../../../markup/editor';
2
+ import type { CodeEditor } from '../../../markup';
3
3
  import type { ToolbarBaseProps } from '../../../toolbar';
4
4
  export declare type MToolbarImagePopupProps = ToolbarBaseProps<CodeEditor> & {
5
5
  hide: () => void;
@@ -1,7 +1,6 @@
1
1
  import React from 'react';
2
2
  import isNumber from 'is-number';
3
- import { IMG_MAX_HEIGHT, getImageDimensions } from '../../../markup';
4
- import { insertImages } from '../../../markup/commands';
3
+ import { IMG_MAX_HEIGHT, getImageDimensions, insertImages } from '../../../markup';
5
4
  import { ToolbarImagePopup } from '../custom/ToolbarImagePopup';
6
5
  import { useMarkupToolbarContext } from './context';
7
6
  const noop = (err) => {
@@ -24,13 +23,13 @@ export const MToolbarImagePopup = ({ focus, onClick, hide, anchorRef, editor, cl
24
23
  insertImages(images)(editor.cm);
25
24
  } }));
26
25
  };
27
- async function toImageItems(items, withDimmensions) {
26
+ async function toImageItems(items, withDimensions) {
28
27
  const imgItems = [];
29
28
  await Promise.all(items.map(({ result, file }) => {
30
29
  var _a;
31
30
  const imgItem = { url: result.url, alt: (_a = result.name) !== null && _a !== void 0 ? _a : file.name };
32
31
  imgItems.push(imgItem);
33
- if (withDimmensions) {
32
+ if (withDimensions) {
34
33
  return getImageDimensions(file).then(({ height }) => {
35
34
  imgItem.height = String(Math.min(height, IMG_MAX_HEIGHT));
36
35
  }, noop);
@@ -1,8 +1,8 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import type { MarkupString } from '../common';
3
3
  import type { EscapeConfig, Extension } from '../core';
4
- import type { CreateCodemirrorParams, YfmLangOptions } from '../markup/codemirror';
5
- import type { FileUploadHandler } from '../utils/upload';
4
+ import type { CreateCodemirrorParams, YfmLangOptions } from '../markup';
5
+ import type { FileUploadHandler } from '../utils';
6
6
  import type { ChangeEditorModeOptions } from './Editor';
7
7
  import type { ExtensionsOptions as WysiwygPresetExtensionsOptions } from './wysiwyg-preset';
8
8
  export type { Editor as MarkdownEditorInstance } from './Editor';
@@ -15,6 +15,10 @@ export declare type RenderPreviewParams = {
15
15
  md: Readonly<MarkdownEditorMdOptions>;
16
16
  };
17
17
  export declare type RenderPreview = (params: RenderPreviewParams) => ReactNode;
18
+ export declare type ParseInsertedUrlAsImage = (text: string) => {
19
+ imageUrl: string;
20
+ title?: string;
21
+ } | null;
18
22
  export declare type MarkdownEditorMdOptions = {
19
23
  html?: boolean;
20
24
  breaks?: boolean;
@@ -45,6 +49,12 @@ export declare type MarkdownEditorExperimentalOptions = {
45
49
  * @default false
46
50
  */
47
51
  needToSetDimensionsForUploadedImages?: boolean;
52
+ /**
53
+ * If we need to enable new image size calculations
54
+ *
55
+ * @default false
56
+ */
57
+ enableNewImageSizeCalculation?: boolean;
48
58
  /**
49
59
  * Called before switching from the markup editor to the wysiwyg editor.
50
60
  * You can use it to pre-process the value from the markup editor before it gets into the wysiwyg editor.
@@ -85,6 +95,10 @@ export declare type MarkdownEditorMarkupConfig = {
85
95
  languageData?: YfmLangOptions['languageData'];
86
96
  /** Config for @codemirror/autocomplete https://codemirror.net/docs/ref/#autocomplete.autocompletion%5Econfig */
87
97
  autocompletion?: CreateCodemirrorParams['autocompletion'];
98
+ /**
99
+ * The function, used to determine if the pasted text is the image url and should be inserted as an image
100
+ */
101
+ parseInsertedUrlAsImage?: ParseInsertedUrlAsImage;
88
102
  };
89
103
  declare type ExtensionsOptions<T extends object = {}> = Omit<WysiwygPresetExtensionsOptions, 'reactRenderer'> & T;
90
104
  export declare type MarkdownEditorWysiwygConfig = {
@@ -13,6 +13,7 @@ export function useMarkdownEditor(props, deps = []) {
13
13
  const renderStorage = new ReactRenderStorage();
14
14
  const uploadFile = (_c = handlers.uploadFile) !== null && _c !== void 0 ? _c : props.fileUploadHandler;
15
15
  const needToSetDimensionsForUploadedImages = (_d = experimental.needToSetDimensionsForUploadedImages) !== null && _d !== void 0 ? _d : props.needToSetDimensionsForUploadedImages;
16
+ const enableNewImageSizeCalculation = experimental.enableNewImageSizeCalculation;
16
17
  const extensions = (builder) => {
17
18
  var _a;
18
19
  const extensionOptions = (_a = wysiwygConfig.extensionOptions) !== null && _a !== void 0 ? _a : props.extensionOptions;
@@ -22,7 +23,8 @@ export function useMarkdownEditor(props, deps = []) {
22
23
  }, onSubmit: () => {
23
24
  editor.emit('submit', null);
24
25
  return true;
25
- }, mdBreaks: breaks, fileUploadHandler: uploadFile, needToSetDimensionsForUploadedImages }));
26
+ }, mdBreaks: breaks, fileUploadHandler: uploadFile, needToSetDimensionsForUploadedImages,
27
+ enableNewImageSizeCalculation }));
26
28
  {
27
29
  const extraExtensions = wysiwygConfig.extensions || props.extraExtensions;
28
30
  if (extraExtensions) {
@@ -31,7 +33,8 @@ export function useMarkdownEditor(props, deps = []) {
31
33
  }
32
34
  };
33
35
  return new EditorImpl(Object.assign(Object.assign({}, props), { preset,
34
- renderStorage, md: Object.assign(Object.assign({}, md), { breaks, html: (_e = md.html) !== null && _e !== void 0 ? _e : props.allowHTML, linkify: (_f = md.linkify) !== null && _f !== void 0 ? _f : props.linkify, linkifyTlds: (_g = md.linkifyTlds) !== null && _g !== void 0 ? _g : props.linkifyTlds }), initial: Object.assign(Object.assign({}, initial), { markup: (_h = initial.markup) !== null && _h !== void 0 ? _h : props.initialMarkup, mode: (_j = initial.mode) !== null && _j !== void 0 ? _j : props.initialEditorMode, toolbarVisible: (_k = initial.toolbarVisible) !== null && _k !== void 0 ? _k : props.initialToolbarVisible, splitModeEnabled: (_l = initial.splitModeEnabled) !== null && _l !== void 0 ? _l : props.initialSplitModeEnabled }), handlers: Object.assign(Object.assign({}, handlers), { uploadFile }), experimental: Object.assign(Object.assign({}, experimental), { needToSetDimensionsForUploadedImages, prepareRawMarkup: (_m = experimental.prepareRawMarkup) !== null && _m !== void 0 ? _m : props.prepareRawMarkup, beforeEditorModeChange: (_o = experimental.beforeEditorModeChange) !== null && _o !== void 0 ? _o : props.experimental_beforeEditorModeChange }), markupConfig: Object.assign(Object.assign({}, markupConfig), { splitMode: (_p = markupConfig.splitMode) !== null && _p !== void 0 ? _p : props.splitMode, renderPreview: (_q = markupConfig.renderPreview) !== null && _q !== void 0 ? _q : props.renderPreview, extensions: (_r = markupConfig.extensions) !== null && _r !== void 0 ? _r : props.extraMarkupExtensions }), wysiwygConfig: Object.assign(Object.assign({}, wysiwygConfig), { extensions, escapeConfig: (_s = wysiwygConfig.escapeConfig) !== null && _s !== void 0 ? _s : props.escapeConfig }) }));
36
+ renderStorage, md: Object.assign(Object.assign({}, md), { breaks, html: (_e = md.html) !== null && _e !== void 0 ? _e : props.allowHTML, linkify: (_f = md.linkify) !== null && _f !== void 0 ? _f : props.linkify, linkifyTlds: (_g = md.linkifyTlds) !== null && _g !== void 0 ? _g : props.linkifyTlds }), initial: Object.assign(Object.assign({}, initial), { markup: (_h = initial.markup) !== null && _h !== void 0 ? _h : props.initialMarkup, mode: (_j = initial.mode) !== null && _j !== void 0 ? _j : props.initialEditorMode, toolbarVisible: (_k = initial.toolbarVisible) !== null && _k !== void 0 ? _k : props.initialToolbarVisible, splitModeEnabled: (_l = initial.splitModeEnabled) !== null && _l !== void 0 ? _l : props.initialSplitModeEnabled }), handlers: Object.assign(Object.assign({}, handlers), { uploadFile }), experimental: Object.assign(Object.assign({}, experimental), { needToSetDimensionsForUploadedImages,
37
+ enableNewImageSizeCalculation, prepareRawMarkup: (_m = experimental.prepareRawMarkup) !== null && _m !== void 0 ? _m : props.prepareRawMarkup, beforeEditorModeChange: (_o = experimental.beforeEditorModeChange) !== null && _o !== void 0 ? _o : props.experimental_beforeEditorModeChange }), markupConfig: Object.assign(Object.assign({}, markupConfig), { splitMode: (_p = markupConfig.splitMode) !== null && _p !== void 0 ? _p : props.splitMode, renderPreview: (_q = markupConfig.renderPreview) !== null && _q !== void 0 ? _q : props.renderPreview, extensions: (_r = markupConfig.extensions) !== null && _r !== void 0 ? _r : props.extraMarkupExtensions }), wysiwygConfig: Object.assign(Object.assign({}, wysiwygConfig), { extensions, escapeConfig: (_s = wysiwygConfig.escapeConfig) !== null && _s !== void 0 ? _s : props.escapeConfig }) }));
35
38
  }, deps);
36
39
  useLayoutEffect(() => {
37
40
  function onToolbarAction({ editorMode, id }) {
@@ -15,5 +15,6 @@ export declare type BundlePresetOptions = ExtensionsOptions & EditorModeKeymapOp
15
15
  * @default false
16
16
  */
17
17
  needToSetDimensionsForUploadedImages?: boolean;
18
+ enableNewImageSizeCalculation?: boolean;
18
19
  };
19
20
  export declare const BundlePreset: ExtensionAuto<BundlePresetOptions>;
@@ -12,7 +12,7 @@ import { wCommandMenuConfigByPreset, wSelectionMenuConfigByPreset } from './conf
12
12
  import { emojiDefs } from './emoji';
13
13
  const DEFAULT_IGNORED_KEYS = ['Tab', 'Shift-Tab'];
14
14
  export const BundlePreset = (builder, opts) => {
15
- var _a, _b;
15
+ var _a, _b, _c;
16
16
  const dropCursor = {
17
17
  color: 'var(--g-color-line-brand)',
18
18
  width: 2,
@@ -21,9 +21,11 @@ export const BundlePreset = (builder, opts) => {
21
21
  const isDocEmpty = !node.text && (parent === null || parent === void 0 ? void 0 : parent.type.name) === BaseNode.Doc && parent.childCount === 1;
22
22
  return isDocEmpty ? i18nPlaceholder('doc_empty') : null;
23
23
  } }, opts.baseSchema) });
24
- const commonMarkOptions = Object.assign(Object.assign({}, zeroOptions), { selectionContext: Object.assign({ config: wSelectionMenuConfigByPreset.commonmark }, opts.selectionContext), commandMenu: Object.assign({ actions: wCommandMenuConfigByPreset.commonmark }, opts.commandMenu), breaks: Object.assign({ preferredBreak: (opts.mdBreaks ? 'soft' : 'hard') }, opts.breaks), bold: Object.assign({ boldKey: f.toPM(A.Bold) }, opts.bold), italic: Object.assign({ italicKey: f.toPM(A.Italic) }, opts.italic), code: Object.assign({ codeKey: f.toPM(A.Code) }, opts.code), codeBlock: Object.assign({ codeBlockKey: f.toPM(A.CodeBlock) }, opts.codeBlock), blockquote: Object.assign({ qouteKey: f.toPM(A.Quote) }, opts.blockquote), link: Object.assign({ linkKey: f.toPM(A.Link) }, opts.link), lists: Object.assign({ ulKey: f.toPM(A.BulletList), olKey: f.toPM(A.OrderedList), ulInputRules: { plus: false } }, opts.lists) });
24
+ const commonMarkOptions = Object.assign(Object.assign({}, zeroOptions), { selectionContext: Object.assign({ config: wSelectionMenuConfigByPreset.commonmark }, opts.selectionContext), commandMenu: Object.assign({ actions: wCommandMenuConfigByPreset.commonmark }, opts.commandMenu), breaks: Object.assign({ preferredBreak: (opts.mdBreaks ? 'soft' : 'hard') }, opts.breaks), bold: Object.assign({ boldKey: f.toPM(A.Bold) }, opts.bold), italic: Object.assign({ italicKey: f.toPM(A.Italic) }, opts.italic), code: Object.assign({ codeKey: f.toPM(A.Code) }, opts.code), codeBlock: Object.assign({ codeBlockKey: f.toPM(A.CodeBlock) }, opts.codeBlock), blockquote: Object.assign({ qouteKey: f.toPM(A.Quote) }, opts.blockquote), link: Object.assign({ linkKey: f.toPM(A.Link) }, opts.link), lists: Object.assign({ ulKey: f.toPM(A.BulletList), olKey: f.toPM(A.OrderedList), ulInputRules: { plus: false } }, opts.lists), image: {
25
+ parseInsertedUrlAsImage: (_a = opts.imgSize) === null || _a === void 0 ? void 0 : _a.parseInsertedUrlAsImage,
26
+ } });
25
27
  const defaultOptions = Object.assign(Object.assign({}, commonMarkOptions), { selectionContext: Object.assign({ config: wSelectionMenuConfigByPreset.default }, opts.selectionContext), commandMenu: Object.assign({ actions: wCommandMenuConfigByPreset.default }, opts.commandMenu), strike: Object.assign({ strikeKey: f.toPM(A.Strike) }, opts.strike) });
26
- const yfmOptions = Object.assign(Object.assign({}, defaultOptions), { selectionContext: Object.assign({ config: wSelectionMenuConfigByPreset.yfm }, opts.selectionContext), commandMenu: Object.assign({ actions: wCommandMenuConfigByPreset.yfm }, opts.commandMenu), underline: Object.assign({ underlineKey: f.toPM(A.Underline) }, opts.underline), imgSize: Object.assign({ imageUploadHandler: opts.fileUploadHandler, needToSetDimensionsForUploadedImages: opts.needToSetDimensionsForUploadedImages }, opts.imgSize), checkbox: Object.assign({ checkboxLabelPlaceholder: () => i18nPlaceholder('checkbox') }, opts.checkbox), deflist: {
28
+ const yfmOptions = Object.assign(Object.assign({}, defaultOptions), { selectionContext: Object.assign({ config: wSelectionMenuConfigByPreset.yfm }, opts.selectionContext), commandMenu: Object.assign({ actions: wCommandMenuConfigByPreset.yfm }, opts.commandMenu), underline: Object.assign({ underlineKey: f.toPM(A.Underline) }, opts.underline), imgSize: Object.assign({ imageUploadHandler: opts.fileUploadHandler, needToSetDimensionsForUploadedImages: opts.needToSetDimensionsForUploadedImages, enableNewImageSizeCalculation: opts.enableNewImageSizeCalculation }, opts.imgSize), checkbox: Object.assign({ checkboxLabelPlaceholder: () => i18nPlaceholder('checkbox') }, opts.checkbox), deflist: {
27
29
  deflistTermPlaceholder: () => i18nPlaceholder('deflist_term'),
28
30
  deflistDescPlaceholder: () => i18nPlaceholder('deflist_desc'),
29
31
  }, yfmCut: Object.assign({ yfmCutKey: f.toPM(A.Cut), yfmCutTitlePlaceholder: () => i18nPlaceholder('cut_title'), yfmCutContentPlaceholder: () => i18nPlaceholder('cut_content') }, opts.yfmCut), yfmNote: Object.assign({ yfmNoteKey: f.toPM(A.Note), yfmNoteTitlePlaceholder: () => i18nPlaceholder('note_title') }, opts.yfmNote), yfmTable: Object.assign({ yfmTableCellPlaceholder: () => i18nPlaceholder('table_cell') }, opts.yfmTable), yfmFile: Object.assign({ fileUploadHandler: opts.fileUploadHandler, needToSetDimensionsForUploadedImages: opts.needToSetDimensionsForUploadedImages }, opts.yfmFile), yfmHeading: Object.assign({ h1Key: f.toPM(A.Heading1), h2Key: f.toPM(A.Heading2), h3Key: f.toPM(A.Heading3), h4Key: f.toPM(A.Heading4), h5Key: f.toPM(A.Heading5), h6Key: f.toPM(A.Heading6), headingPlaceholder: (node) => `${i18nPlaceholder('heading')} ${node.attrs[YfmHeadingAttr.Level]}` }, opts.yfmHeading), placeholder: {
@@ -63,7 +65,7 @@ export const BundlePreset = (builder, opts) => {
63
65
  break;
64
66
  }
65
67
  }
66
- const ignoreKeysList = (_b = (_a = opts.ignoreKeysList) === null || _a === void 0 ? void 0 : _a.slice()) !== null && _b !== void 0 ? _b : [];
68
+ const ignoreKeysList = (_c = (_b = opts.ignoreKeysList) === null || _b === void 0 ? void 0 : _b.slice()) !== null && _c !== void 0 ? _c : [];
67
69
  ignoreKeysList.push(...DEFAULT_IGNORED_KEYS);
68
70
  for (const action of ignoreActions) {
69
71
  const key = f.toPM(action);
@@ -309,7 +309,7 @@ export class MarkdownSerializerState {
309
309
  // have special meaning only at the start of the line.
310
310
  esc(str, startOfLine) {
311
311
  var _a, _b;
312
- const escRegexp = ((_a = this.options) === null || _a === void 0 ? void 0 : _a.commonEscape) || /[`\^+*\\\|~\[\]\{\}<>\$]/g;
312
+ const escRegexp = ((_a = this.options) === null || _a === void 0 ? void 0 : _a.commonEscape) || /[`\^+*\\\|~\[\]\{\}<>\$_]/g;
313
313
  const startOfLineEscRegexp = ((_b = this.options) === null || _b === void 0 ? void 0 : _b.startOfLineEscape) || /^[:#\-*+>]/;
314
314
  str = str.replace(escRegexp, '\\$&');
315
315
  if (startOfLine)
@@ -50,9 +50,9 @@ const DiagramEditMode = ({ initialText, onSave, onCancel, mermaidInstance }) =>
50
50
  React.createElement("div", { className: b('Controls') },
51
51
  React.createElement("div", null,
52
52
  React.createElement(Button, { onClick: onCancel, view: 'flat' },
53
- React.createElement("span", { className: cnDiagramHelper({ 'prosemirror-stop-event': true }) }, "Cancel")),
53
+ React.createElement("span", { className: cnDiagramHelper({ 'prosemirror-stop-event': true }) }, i18n('cancel'))),
54
54
  React.createElement(Button, { onClick: () => onSave(text), view: 'action' },
55
- React.createElement("span", { className: cnDiagramHelper({ 'prosemirror-stop-event': true }) }, "Save")))))));
55
+ React.createElement("span", { className: cnDiagramHelper({ 'prosemirror-stop-event': true }) }, i18n('save'))))))));
56
56
  };
57
57
  export const MermaidView = ({ onChange, node, getPos, view, getMermaidInstance }) => {
58
58
  const [mermaidInstance, setMermaidInstance] = useState(null);
@@ -122,10 +122,7 @@ export const CodeBlockHighlight = (builder, opts) => {
122
122
  let from = pos + 1;
123
123
  let nodes;
124
124
  const lang = node.attrs[codeBlockLangAttr];
125
- if (!lang) {
126
- nodes = lowlight.highlightAuto(node.textContent).children;
127
- }
128
- else if (lowlight.registered(lang)) {
125
+ if (lang && lowlight.registered(lang)) {
129
126
  nodes = lowlight.highlight(lang, node.textContent).children;
130
127
  }
131
128
  else {
@@ -52,12 +52,19 @@ export const ImageSpecs = (builder) => {
52
52
  },
53
53
  },
54
54
  toMd: (state, { attrs }) => {
55
- state.write('![' +
56
- state.esc(attrs.alt || '') +
57
- '](' +
58
- state.esc(attrs.src) +
59
- (attrs.title ? ' ' + state.quote(attrs.title) : '') +
60
- ')');
55
+ let result = '![';
56
+ if (attrs.alt) {
57
+ result += state.esc(attrs.alt);
58
+ }
59
+ result += '](';
60
+ if (attrs.src) {
61
+ result += state.esc(attrs.src);
62
+ }
63
+ if (attrs.title) {
64
+ result += ` ${state.quote(attrs.title)}`;
65
+ }
66
+ result += ')';
67
+ state.write(result);
61
68
  },
62
69
  }));
63
70
  };
@@ -0,0 +1,9 @@
1
+ import type { ParseInsertedUrlAsImage } from '../../../../bundle';
2
+ import { ExtensionAuto } from '../../../../core';
3
+ export declare type ImageUrlPasteOptions = {
4
+ /**
5
+ * The function, used to determine if the pasted text is the image url and should be inserted as an image
6
+ */
7
+ parseInsertedUrlAsImage?: ParseInsertedUrlAsImage;
8
+ };
9
+ export declare const imageUrlPaste: ExtensionAuto<ImageUrlPasteOptions>;
@@ -0,0 +1,30 @@
1
+ import { Plugin } from 'prosemirror-state';
2
+ import { DataTransferType } from '../../../behavior/Clipboard/utils';
3
+ import { imageType } from '../ImageSpecs';
4
+ export const imageUrlPaste = (builder, opts) => {
5
+ builder.addPlugin(() => new Plugin({
6
+ props: {
7
+ handleDOMEvents: {
8
+ paste(view, e) {
9
+ var _a;
10
+ if (!opts.parseInsertedUrlAsImage ||
11
+ !e.clipboardData ||
12
+ view.state.selection.$from.parent.type.spec.code)
13
+ return false;
14
+ const { imageUrl, title } = opts.parseInsertedUrlAsImage((_a = e.clipboardData.getData(DataTransferType.Text)) !== null && _a !== void 0 ? _a : '') || {};
15
+ if (!imageUrl) {
16
+ return false;
17
+ }
18
+ e.preventDefault();
19
+ const imageNode = imageType(view.state.schema).create({
20
+ src: imageUrl,
21
+ alt: title,
22
+ });
23
+ const tr = view.state.tr.replaceSelectionWith(imageNode);
24
+ view.dispatch(tr.scrollIntoView());
25
+ return true;
26
+ },
27
+ },
28
+ },
29
+ }), builder.Priority.High);
30
+ };
@@ -1,11 +1,13 @@
1
1
  import type { Action, ExtensionAuto } from '../../../core';
2
2
  import { AddImageAttrs } from './actions';
3
3
  import { addImageAction } from './const';
4
+ import { ImageUrlPasteOptions } from './imageUrlPaste';
4
5
  export { imageNodeName, imageType, ImageAttr } from './ImageSpecs';
5
6
  /** @deprecated Use `imageType` instead */
6
7
  export declare const imgType: (schema: import("prosemirror-model").Schema<any, any>) => import("prosemirror-model").NodeType;
7
8
  export type { AddImageAttrs } from './actions';
8
- export declare const Image: ExtensionAuto;
9
+ export declare type ImageOptions = ImageUrlPasteOptions;
10
+ export declare const Image: ExtensionAuto<ImageOptions | undefined>;
9
11
  declare global {
10
12
  namespace WysiwygEditor {
11
13
  interface Actions {
@@ -1,10 +1,17 @@
1
+ import { isFunction } from '../../../lodash';
1
2
  import { ImageSpecs, imageType } from './ImageSpecs';
2
3
  import { addImage } from './actions';
3
4
  import { addImageAction } from './const';
5
+ import { imageUrlPaste } from './imageUrlPaste';
4
6
  export { imageNodeName, imageType, ImageAttr } from './ImageSpecs';
5
7
  /** @deprecated Use `imageType` instead */
6
8
  export const imgType = imageType;
7
- export const Image = (builder) => {
9
+ export const Image = (builder, opts) => {
8
10
  builder.use(ImageSpecs);
9
11
  builder.addAction(addImageAction, ({ schema }) => addImage(schema));
12
+ if (isFunction(opts === null || opts === void 0 ? void 0 : opts.parseInsertedUrlAsImage)) {
13
+ builder.use(imageUrlPaste, {
14
+ parseInsertedUrlAsImage: opts.parseInsertedUrlAsImage,
15
+ });
16
+ }
10
17
  };
@@ -6,7 +6,7 @@ export declare type ListsInputRulesOptions = {
6
6
  export declare const ListsInputRulesExtension: ExtensionWithOptions<ListsInputRulesOptions>;
7
7
  /**
8
8
  * Given a list node type, returns an input rule that turns a number
9
- * followed by a dot at the start of a textblock into an ordered list.
9
+ * followed by a dot or parenthesis at the start of a textblock into an ordered list.
10
10
  */
11
11
  export declare function orderedListRule(nodeType: NodeType): import("prosemirror-inputrules").InputRule;
12
12
  declare type BulletListInputRuleConfig = {
@@ -14,10 +14,13 @@ export const ListsInputRulesExtension = (builder, options) => {
14
14
  };
15
15
  /**
16
16
  * Given a list node type, returns an input rule that turns a number
17
- * followed by a dot at the start of a textblock into an ordered list.
17
+ * followed by a dot or parenthesis at the start of a textblock into an ordered list.
18
18
  */
19
19
  export function orderedListRule(nodeType) {
20
- return wrappingInputRule(/^(\d+)\.\s$/, nodeType, (match) => ({ [ListsAttr.Order]: Number(match[1]) }), (match, node) => node.childCount + node.attrs[ListsAttr.Order] === Number(match[1]));
20
+ return wrappingInputRule(/^(\d+)([.)])\s$/, nodeType, (match) => ({
21
+ [ListsAttr.Order]: Number(match[1]),
22
+ [ListsAttr.Markup]: match[2],
23
+ }), (match, node) => node.childCount + node.attrs[ListsAttr.Order] === Number(match[1]));
21
24
  }
22
25
  /**
23
26
  * Given a list node type, returns an input rule that turns a bullet
@@ -1,7 +1,6 @@
1
1
  import React from 'react';
2
2
  import { List, Popup } from '@gravity-ui/uikit';
3
3
  import { cn } from '../../../../classname';
4
- import { i18n } from '../../../../i18n/suggest';
5
4
  import { ErrorLoggerBoundary } from '../../../../react-utils/ErrorBoundary';
6
5
  import './EmojiSuggestComponent.css';
7
6
  const b = cn('emoji-suggest');
@@ -17,9 +16,9 @@ function calcListHeight(itemsCount) {
17
16
  export const EmojiSuggestComponent = ({ anchor, currentIndex, items, onClick, onEnterKeyDown, onEscapeKeyDown, onOutsideClick, }) => {
18
17
  if (!anchor)
19
18
  return null;
20
- return (React.createElement(Popup, { open: true, anchorRef: { current: anchor }, placement: placement, onEnterKeyDown: onEnterKeyDown, onEscapeKeyDown: onEscapeKeyDown, onOutsideClick: onOutsideClick },
19
+ return (React.createElement(Popup, { open: Boolean(items.length), anchorRef: { current: anchor }, placement: placement, onEnterKeyDown: onEnterKeyDown, onEscapeKeyDown: onEscapeKeyDown, onOutsideClick: onOutsideClick },
21
20
  React.createElement("div", { className: b() },
22
- React.createElement(List, { virtualized: true, items: items, sortable: false, filterable: false, emptyPlaceholder: i18n('empty-msg'), itemHeight: ITEM_HEIGHT, itemsHeight: calcListHeight(items.length), renderItem: renderItem, deactivateOnLeave: false, activeItemIndex: currentIndex, onItemClick: (_item, index) => onClick(index), className: b('list'), itemClassName: b('list-item') }))));
21
+ React.createElement(List, { virtualized: true, items: items, sortable: false, filterable: false, itemHeight: ITEM_HEIGHT, itemsHeight: calcListHeight(items.length), renderItem: renderItem, deactivateOnLeave: false, activeItemIndex: currentIndex, onItemClick: (_item, index) => onClick(index), className: b('list'), itemClassName: b('list-item') }))));
23
22
  };
24
23
  function renderItem({ origName, symbol, origShortcuts }) {
25
24
  return (React.createElement("div", { key: origName, className: b('item') },
@@ -1,7 +1,12 @@
1
+ import type { ParseInsertedUrlAsImage } from '../../../../bundle';
1
2
  import { ExtensionAuto } from '../../../../core';
2
- import { FileUploadHandler } from '../../../../utils/upload';
3
+ import { FileUploadHandler } from '../../../../utils';
3
4
  import { CreateImageNodeOptions } from '../utils';
4
- export declare type ImagePasteOptions = Pick<CreateImageNodeOptions, 'needDimmensions'> & {
5
- imageUploadHandler: FileUploadHandler;
5
+ export declare type ImagePasteOptions = Pick<CreateImageNodeOptions, 'needDimensions' | 'enableNewImageSizeCalculation'> & {
6
+ imageUploadHandler?: FileUploadHandler;
7
+ /**
8
+ * The function, used to determine if the pasted text is the image url and should be inserted as an image
9
+ */
10
+ parseInsertedUrlAsImage?: ParseInsertedUrlAsImage;
6
11
  };
7
12
  export declare const ImagePaste: ExtensionAuto<ImagePasteOptions>;
@@ -4,27 +4,47 @@ import { Plugin } from 'prosemirror-state';
4
4
  import { dropPoint } from 'prosemirror-transform';
5
5
  import { isFunction } from '../../../../lodash';
6
6
  import { clipboardUtils } from '../../../behavior/Clipboard';
7
+ import { DataTransferType } from '../../../behavior/Clipboard/utils';
7
8
  import { ImageAttr, ImgSizeAttr, imageType } from '../../../specs';
8
9
  import { isImageNode } from '../utils';
9
10
  import { ImagesUploadProcess } from './upload';
10
11
  const { isFilesFromHtml, isFilesOnly, isImageFile } = clipboardUtils;
11
12
  export const ImagePaste = (builder, opts) => {
12
- if (!opts || !isFunction(opts.imageUploadHandler))
13
- throw new Error('ImagePaste extension: imageUploadHandler is not a function');
13
+ const { parseInsertedUrlAsImage, imageUploadHandler } = opts !== null && opts !== void 0 ? opts : {};
14
+ if (!isFunction(imageUploadHandler !== null && imageUploadHandler !== void 0 ? imageUploadHandler : parseInsertedUrlAsImage))
15
+ throw new Error(`ImagePaste extension: ${opts.imageUploadHandler ? 'imageUploadHandler' : 'parseInsertedUrlAsImage'} is not a function`);
14
16
  builder.addPlugin(() => new Plugin({
15
17
  props: {
16
18
  handleDOMEvents: {
17
19
  paste(view, e) {
20
+ var _a, _b;
18
21
  const files = getPastedImages(e.clipboardData);
19
- if (files) {
22
+ if (imageUploadHandler && files) {
23
+ e.preventDefault();
24
+ new ImagesUploadProcess(view, files, imageUploadHandler, view.state.tr.selection.from, opts).run();
25
+ return true;
26
+ }
27
+ else if (parseInsertedUrlAsImage) {
28
+ const { imageUrl, title } = parseInsertedUrlAsImage((_b = (_a = e.clipboardData) === null || _a === void 0 ? void 0 : _a.getData(DataTransferType.Text)) !== null && _b !== void 0 ? _b : '') || {};
29
+ if (!imageUrl) {
30
+ return false;
31
+ }
20
32
  e.preventDefault();
21
- new ImagesUploadProcess(view, files, opts.imageUploadHandler, view.state.tr.selection.from, opts).run();
33
+ const imageNode = imageType(view.state.schema).create({
34
+ src: imageUrl,
35
+ alt: title,
36
+ });
37
+ const tr = view.state.tr.replaceSelectionWith(imageNode);
38
+ view.dispatch(tr.scrollIntoView());
22
39
  return true;
23
40
  }
24
41
  return false;
25
42
  },
26
43
  drop(view, e) {
27
44
  var _a, _b;
45
+ if (!imageUploadHandler) {
46
+ return false;
47
+ }
28
48
  // handle drop images from device
29
49
  if (view.dragging)
30
50
  return false;
@@ -36,19 +56,22 @@ export const ImagePaste = (builder, opts) => {
36
56
  return false;
37
57
  const posToInsert = dropPoint(view.state.doc, dropPos, createFakeImageSlice(view.state.schema));
38
58
  if (posToInsert !== null) {
39
- new ImagesUploadProcess(view, files, opts.imageUploadHandler, posToInsert, opts).run();
59
+ new ImagesUploadProcess(view, files, imageUploadHandler, posToInsert, opts).run();
40
60
  }
41
61
  e.preventDefault();
42
62
  return true;
43
63
  },
44
64
  },
45
65
  handlePaste(view, _event, slice) {
66
+ if (!imageUploadHandler) {
67
+ return false;
68
+ }
46
69
  const node = sliceSingleNode(slice);
47
70
  if (node && isImageNode(node)) {
48
71
  const imgUrl = node.attrs[ImgSizeAttr.Src];
49
72
  const imgFile = dataUrlToFile(imgUrl, 'image');
50
73
  if (imgFile) {
51
- new ImagesUploadProcess(view, [imgFile], opts.imageUploadHandler, view.state.tr.selection.from, opts).run();
74
+ new ImagesUploadProcess(view, [imgFile], imageUploadHandler, view.state.tr.selection.from, opts).run();
52
75
  return true;
53
76
  }
54
77
  }
@@ -1,12 +1,13 @@
1
1
  import { Node } from 'prosemirror-model';
2
2
  import { EditorView } from 'prosemirror-view';
3
- import { FileUploadHandler, UploadSuccessItem } from '../../../../utils/upload';
3
+ import { FileUploadHandler, UploadSuccessItem } from '../../../../utils';
4
4
  import { FilesBatchUploadProcess } from '../../../behavior/utils/upload';
5
5
  import { CreateImageNodeOptions } from '../utils';
6
6
  import { ImageSkeletonDescriptor } from './skeleton';
7
7
  export declare class ImagesUploadProcess extends FilesBatchUploadProcess {
8
8
  protected readonly createImage: ({ result, file }: UploadSuccessItem) => Promise<Node>;
9
9
  protected readonly initPosition: number;
10
+ private readonly enableNewImageSizeCalculation?;
10
11
  constructor(view: EditorView, files: readonly File[], uploadHandler: FileUploadHandler, position: number, opts: CreateImageNodeOptions);
11
12
  protected createSkeleton(): Promise<ImageSkeletonDescriptor>;
12
13
  protected createPMNode(res: UploadSuccessItem): Promise<Node>;
@@ -1,4 +1,5 @@
1
1
  import { logger } from '../../../../logger';
2
+ import { getProportionalSize } from '../../../../utils';
2
3
  import { FilesBatchUploadProcess } from '../../../behavior/utils/upload';
3
4
  import { imageType } from '../../../markdown';
4
5
  import { IMG_MAX_HEIGHT } from '../const';
@@ -9,19 +10,22 @@ export class ImagesUploadProcess extends FilesBatchUploadProcess {
9
10
  super(view, files, uploadHandler);
10
11
  this.initPosition = position;
11
12
  this.createImage = createImageNode(imageType(this.view.state.schema), opts);
13
+ this.enableNewImageSizeCalculation = opts.enableNewImageSizeCalculation;
12
14
  }
13
15
  async createSkeleton() {
14
- return new ImageSkeletonDescriptor(this.initPosition, await getSkeletonSize(this.files));
16
+ return new ImageSkeletonDescriptor(this.initPosition, await getSkeletonSize(this.files, {
17
+ enableNewImageSizeCalculation: this.enableNewImageSizeCalculation,
18
+ }));
15
19
  }
16
20
  async createPMNode(res) {
17
21
  return this.createImage(res);
18
22
  }
19
23
  }
20
- async function getSkeletonSize(files) {
24
+ async function getSkeletonSize(files, opts) {
21
25
  const skeletonSize = { width: '300', height: '200' };
22
26
  if (files.length === 1) {
23
27
  try {
24
- const size = await loadImage(files[0]).then(calcSkeletonSize);
28
+ const size = await loadImage(files[0]).then((opts === null || opts === void 0 ? void 0 : opts.enableNewImageSizeCalculation) ? calcSkeletonSizeNew : calcSkeletonSize);
25
29
  skeletonSize.width = String(size.width);
26
30
  skeletonSize.height = String(size.height);
27
31
  }
@@ -31,10 +35,16 @@ async function getSkeletonSize(files) {
31
35
  }
32
36
  return skeletonSize;
33
37
  }
34
- function calcSkeletonSize(img) {
35
- const { width, height } = img;
38
+ function calcSkeletonSize({ width, height }) {
36
39
  if (height <= IMG_MAX_HEIGHT)
37
40
  return { width, height };
38
41
  const ratio = IMG_MAX_HEIGHT / height; // ratio<1
39
42
  return { height: IMG_MAX_HEIGHT, width: width * ratio };
40
43
  }
44
+ function calcSkeletonSizeNew({ width, height }) {
45
+ return getProportionalSize({
46
+ width,
47
+ height,
48
+ imgMaxHeight: IMG_MAX_HEIGHT,
49
+ });
50
+ }