@gravity-ui/markdown-editor 14.0.3 → 14.2.1
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/build/cjs/bundle/Editor.d.ts +1 -1
- package/build/cjs/bundle/Editor.js +19 -7
- package/build/cjs/bundle/config/action-names.d.ts +1 -1
- package/build/cjs/bundle/toolbar/markup/MToolbarImagePopup.d.ts +1 -1
- package/build/cjs/bundle/toolbar/markup/MToolbarImagePopup.js +4 -5
- package/build/cjs/bundle/types.d.ts +16 -2
- package/build/cjs/bundle/useMarkdownEditor.js +5 -2
- package/build/cjs/bundle/wysiwyg-preset.d.ts +1 -0
- package/build/cjs/bundle/wysiwyg-preset.js +6 -4
- package/build/cjs/extensions/additional/Mermaid/MermaidNodeView/MermaidView.js +2 -2
- package/build/cjs/extensions/markdown/CodeBlock/CodeBlockHighlight/CodeBlockHighlight.js +1 -4
- package/build/cjs/extensions/markdown/Image/ImageSpecs/index.js +13 -6
- package/build/cjs/extensions/markdown/Image/imageUrlPaste/index.d.ts +9 -0
- package/build/cjs/extensions/markdown/Image/imageUrlPaste/index.js +34 -0
- package/build/cjs/extensions/markdown/Image/index.d.ts +3 -1
- package/build/cjs/extensions/markdown/Image/index.js +8 -1
- package/build/cjs/extensions/markdown/Lists/inputrules.d.ts +1 -1
- package/build/cjs/extensions/markdown/Lists/inputrules.js +5 -2
- package/build/cjs/extensions/yfm/Emoji/EmojiSuggest/EmojiSuggestComponent.js +2 -3
- package/build/cjs/extensions/yfm/ImgSize/ImagePaste/index.d.ts +8 -3
- package/build/cjs/extensions/yfm/ImgSize/ImagePaste/index.js +31 -8
- package/build/cjs/extensions/yfm/ImgSize/ImagePaste/upload.d.ts +2 -1
- package/build/cjs/extensions/yfm/ImgSize/ImagePaste/upload.js +17 -7
- package/build/cjs/extensions/yfm/ImgSize/ImageWidget/widget.js +1 -1
- package/build/cjs/extensions/yfm/ImgSize/ImgSizeSpecs/index.js +15 -8
- package/build/cjs/extensions/yfm/ImgSize/index.d.ts +2 -3
- package/build/cjs/extensions/yfm/ImgSize/index.js +4 -2
- package/build/cjs/extensions/yfm/ImgSize/plugins/ImgSizeNodeView/NodeView.js +10 -2
- package/build/cjs/extensions/yfm/ImgSize/utils.d.ts +6 -2
- package/build/cjs/extensions/yfm/ImgSize/utils.js +13 -3
- package/build/cjs/extensions/yfm/Video/VideoSpecs/index.js +1 -1
- package/build/cjs/extensions/yfm/YfmFile/YfmFilePaste/index.d.ts +1 -1
- package/build/cjs/extensions/yfm/YfmFile/YfmFilePaste/index.js +1 -1
- package/build/cjs/i18n/menubar/index.d.ts +1 -1
- package/build/cjs/i18n/placeholder/index.d.ts +1 -1
- package/build/cjs/i18n/yfm-note/index.d.ts +1 -1
- package/build/cjs/markup/codemirror/create.d.ts +4 -1
- package/build/cjs/markup/codemirror/create.js +21 -2
- package/build/cjs/markup/codemirror/files-upload-facet.d.ts +4 -2
- package/build/cjs/markup/codemirror/files-upload-plugin/plugin.js +30 -19
- package/build/cjs/markup/codemirror/files-upload-plugin/utils.js +4 -4
- package/build/cjs/markup/codemirror/yfm.d.ts +1 -1
- package/build/cjs/markup/commands/inline.js +9 -3
- package/build/cjs/presets/commonmark.d.ts +2 -2
- package/build/cjs/presets/commonmark.js +1 -1
- package/build/cjs/utils/get-proportional-size.d.ts +10 -0
- package/build/cjs/utils/get-proportional-size.js +14 -0
- package/build/cjs/utils/index.d.ts +2 -1
- package/build/cjs/utils/index.js +2 -7
- package/build/cjs/version.js +1 -1
- package/build/esm/bundle/Editor.d.ts +1 -1
- package/build/esm/bundle/Editor.js +17 -5
- package/build/esm/bundle/config/action-names.d.ts +1 -1
- package/build/esm/bundle/toolbar/markup/MToolbarImagePopup.d.ts +1 -1
- package/build/esm/bundle/toolbar/markup/MToolbarImagePopup.js +3 -4
- package/build/esm/bundle/types.d.ts +16 -2
- package/build/esm/bundle/useMarkdownEditor.js +5 -2
- package/build/esm/bundle/wysiwyg-preset.d.ts +1 -0
- package/build/esm/bundle/wysiwyg-preset.js +6 -4
- package/build/esm/extensions/additional/Mermaid/MermaidNodeView/MermaidView.js +2 -2
- package/build/esm/extensions/markdown/CodeBlock/CodeBlockHighlight/CodeBlockHighlight.js +1 -4
- package/build/esm/extensions/markdown/Image/ImageSpecs/index.js +13 -6
- package/build/esm/extensions/markdown/Image/imageUrlPaste/index.d.ts +9 -0
- package/build/esm/extensions/markdown/Image/imageUrlPaste/index.js +30 -0
- package/build/esm/extensions/markdown/Image/index.d.ts +3 -1
- package/build/esm/extensions/markdown/Image/index.js +8 -1
- package/build/esm/extensions/markdown/Lists/inputrules.d.ts +1 -1
- package/build/esm/extensions/markdown/Lists/inputrules.js +5 -2
- package/build/esm/extensions/yfm/Emoji/EmojiSuggest/EmojiSuggestComponent.js +2 -3
- package/build/esm/extensions/yfm/ImgSize/ImagePaste/index.d.ts +8 -3
- package/build/esm/extensions/yfm/ImgSize/ImagePaste/index.js +29 -6
- package/build/esm/extensions/yfm/ImgSize/ImagePaste/upload.d.ts +2 -1
- package/build/esm/extensions/yfm/ImgSize/ImagePaste/upload.js +15 -5
- package/build/esm/extensions/yfm/ImgSize/ImageWidget/widget.js +1 -1
- package/build/esm/extensions/yfm/ImgSize/ImgSizeSpecs/index.js +15 -8
- package/build/esm/extensions/yfm/ImgSize/index.d.ts +2 -3
- package/build/esm/extensions/yfm/ImgSize/index.js +4 -2
- package/build/esm/extensions/yfm/ImgSize/plugins/ImgSizeNodeView/NodeView.js +10 -2
- package/build/esm/extensions/yfm/ImgSize/utils.d.ts +6 -2
- package/build/esm/extensions/yfm/ImgSize/utils.js +11 -2
- package/build/esm/extensions/yfm/Video/VideoSpecs/index.js +1 -1
- package/build/esm/extensions/yfm/YfmFile/YfmFilePaste/index.d.ts +1 -1
- package/build/esm/extensions/yfm/YfmFile/YfmFilePaste/index.js +1 -1
- package/build/esm/i18n/menubar/index.d.ts +1 -1
- package/build/esm/i18n/placeholder/index.d.ts +1 -1
- package/build/esm/i18n/yfm-note/index.d.ts +1 -1
- package/build/esm/markup/codemirror/create.d.ts +4 -1
- package/build/esm/markup/codemirror/create.js +22 -3
- package/build/esm/markup/codemirror/files-upload-facet.d.ts +4 -2
- package/build/esm/markup/codemirror/files-upload-plugin/plugin.js +22 -11
- package/build/esm/markup/codemirror/files-upload-plugin/utils.js +1 -1
- package/build/esm/markup/codemirror/yfm.d.ts +1 -1
- package/build/esm/markup/commands/inline.js +9 -3
- package/build/esm/presets/commonmark.d.ts +2 -2
- package/build/esm/presets/commonmark.js +1 -1
- package/build/esm/utils/get-proportional-size.d.ts +10 -0
- package/build/esm/utils/get-proportional-size.js +10 -0
- package/build/esm/utils/index.d.ts +2 -1
- package/build/esm/utils/index.js +2 -1
- package/build/esm/version.js +1 -1
- package/package.json +10 -7
package/build/cjs/version.js
CHANGED
|
@@ -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.
|
|
5
|
+
exports.VERSION = typeof '14.2.1' !== 'undefined' ? '14.2.1' : 'unknown';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CommonEditor } from '../common';
|
|
2
2
|
import { ReactRenderStorage } from '../extensions';
|
|
3
|
-
import { type Receiver } from '../utils
|
|
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
|
|
8
|
+
import { createCodemirror } from '../markup';
|
|
9
9
|
import { Editor as MarkupEditor } from '../markup/editor';
|
|
10
|
-
import { SafeEventEmitter } from '../utils
|
|
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
|
-
|
|
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" | "
|
|
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
|
|
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,
|
|
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 (
|
|
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
|
|
5
|
-
import type { FileUploadHandler } from '../utils
|
|
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,
|
|
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 = (
|
|
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);
|
|
@@ -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 }) },
|
|
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 }) },
|
|
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 (
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
let result = ' {
|
|
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
|
|
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+)
|
|
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:
|
|
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,
|
|
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
|
|
3
|
+
import { FileUploadHandler } from '../../../../utils';
|
|
3
4
|
import { CreateImageNodeOptions } from '../utils';
|
|
4
|
-
export declare type ImagePasteOptions = Pick<CreateImageNodeOptions, '
|
|
5
|
-
imageUploadHandler
|
|
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
|
-
|
|
13
|
-
|
|
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
|
-
|
|
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,
|
|
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],
|
|
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
|
|
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(
|
|
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
|
+
}
|
|
@@ -73,7 +73,7 @@ class ImageWidgetHandler {
|
|
|
73
73
|
return;
|
|
74
74
|
const { view } = this;
|
|
75
75
|
new ImagesUploadProcess(view, files, this.uploadImages, this.getPos(), {
|
|
76
|
-
|
|
76
|
+
needDimensions: this.needToSetDimensionsForUploadedImages,
|
|
77
77
|
}).run();
|
|
78
78
|
view.dispatch(removeWidget(view.state.tr, this.decoId));
|
|
79
79
|
view.focus();
|