@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
@@ -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
- needDimmensions: this.needToSetDimensionsForUploadedImages,
76
+ needDimensions: this.needToSetDimensionsForUploadedImages,
77
77
  }).run();
78
78
  view.dispatch(removeWidget(view.state.tr, this.decoId));
79
79
  view.focus();
@@ -7,7 +7,7 @@ export { ImgSizeAttr };
7
7
  export const ImgSizeSpecs = (builder, opts) => {
8
8
  var _a;
9
9
  const placeholderContent = (_a = builder.context.get('placeholder')) === null || _a === void 0 ? void 0 : _a.imgSize;
10
- builder.configureMd((md) => md.use(imsize, { log }));
10
+ builder.configureMd((md) => md.use(imsize, { log, enableInlineStyling: true }));
11
11
  builder.addNode(imageNodeName, () => ({
12
12
  spec: {
13
13
  inline: true,
@@ -62,13 +62,20 @@ export const ImgSizeSpecs = (builder, opts) => {
62
62
  },
63
63
  toMd: (state, node) => {
64
64
  const attrs = node.attrs;
65
- state.write('![' +
66
- state.esc(attrs.alt || '') +
67
- '](' +
68
- state.esc(attrs.src) +
69
- (attrs.title ? ' ' + state.quote(attrs.title) : '') +
70
- getSize(attrs) +
71
- ')');
65
+ let result = '![';
66
+ if (attrs.alt) {
67
+ result += state.esc(attrs.alt);
68
+ }
69
+ result += '](';
70
+ if (attrs.src) {
71
+ result += state.esc(attrs.src);
72
+ }
73
+ if (attrs.title) {
74
+ result += ` ${state.quote(attrs.title)}`;
75
+ }
76
+ result += getSize(attrs);
77
+ result += ')';
78
+ state.write(result);
72
79
  },
73
80
  }));
74
81
  };
@@ -1,17 +1,16 @@
1
1
  import type { Action, ExtensionAuto } from '../../../core';
2
- import type { FileUploadHandler } from '../../../utils';
2
+ import { ImagePasteOptions } from './ImagePaste';
3
3
  import { ImgSizeSpecsOptions } from './ImgSizeSpecs';
4
4
  import { AddImageAttrs } from './actions';
5
5
  import { addImageAction } from './const';
6
6
  export declare type ImgSizeOptions = ImgSizeSpecsOptions & {
7
- imageUploadHandler?: FileUploadHandler;
8
7
  /**
9
8
  * If we need to set dimensions for uploaded images
10
9
  *
11
10
  * @default false
12
11
  */
13
12
  needToSetDimensionsForUploadedImages?: boolean;
14
- };
13
+ } & Pick<ImagePasteOptions, 'imageUploadHandler' | 'parseInsertedUrlAsImage' | 'enableNewImageSizeCalculation'>;
15
14
  export declare const ImgSize: ExtensionAuto<ImgSizeOptions>;
16
15
  declare global {
17
16
  namespace WysiwygEditor {
@@ -10,10 +10,12 @@ export const ImgSize = (builder, opts) => {
10
10
  imageUploadHandler: opts.imageUploadHandler,
11
11
  needToSetDimensionsForUploadedImages: Boolean(opts.needToSetDimensionsForUploadedImages),
12
12
  });
13
- if (opts.imageUploadHandler) {
13
+ if (opts.imageUploadHandler || opts.parseInsertedUrlAsImage) {
14
14
  builder.use(ImagePaste, {
15
15
  imageUploadHandler: opts.imageUploadHandler,
16
- needDimmensions: Boolean(opts.needToSetDimensionsForUploadedImages),
16
+ needDimensions: Boolean(opts.needToSetDimensionsForUploadedImages),
17
+ parseInsertedUrlAsImage: opts.parseInsertedUrlAsImage,
18
+ enableNewImageSizeCalculation: opts.enableNewImageSizeCalculation,
17
19
  });
18
20
  }
19
21
  builder.addAction(addImageAction, ({ schema }) => addImage(schema));
@@ -37,10 +37,18 @@ export const ImageNodeView = ({ node, view, getPos, updateAttributes, }) => {
37
37
  onResize: handleResize,
38
38
  });
39
39
  const style = {
40
- width: state.width ? `${state.width}px` : '',
41
- height: state.height ? `${state.height}px` : '',
42
40
  transition: 'width 0.15s ease-out, height 0.15s ease-out',
43
41
  };
42
+ if (state.width) {
43
+ style.width = `${state.width}px`;
44
+ if (state.height) {
45
+ style.aspectRatio = state.width / state.height;
46
+ style.height = 'auto;';
47
+ }
48
+ }
49
+ else if (state.height) {
50
+ style.height = `${state.height}px`;
51
+ }
44
52
  const handleDelete = useCallback(() => {
45
53
  const pos = getPos();
46
54
  if (pos === undefined)
@@ -1,13 +1,17 @@
1
1
  import { Node, NodeType } from 'prosemirror-model';
2
- import { UploadSuccessItem } from '../../../utils/upload';
2
+ import { UploadSuccessItem } from '../../../utils';
3
3
  import { ImgSizeAttr } from '../../specs';
4
4
  export declare function isImageNode(node: Node): boolean;
5
5
  export declare type CreateImageNodeOptions = {
6
- needDimmensions: boolean;
6
+ needDimensions: boolean;
7
+ enableNewImageSizeCalculation?: boolean;
7
8
  };
8
9
  export declare const createImageNode: (imgType: NodeType, opts: CreateImageNodeOptions) => ({ result, file }: UploadSuccessItem) => Promise<Node>;
9
10
  export declare function loadImage(imgFile: File): Promise<HTMLImageElement>;
10
11
  export declare function getImageSize(img: HTMLImageElement): {
12
+ [ImgSizeAttr.Height]?: string;
13
+ };
14
+ export declare function getImageSizeNew({ width, height }: HTMLImageElement): {
11
15
  [ImgSizeAttr.Width]?: string;
12
16
  [ImgSizeAttr.Height]?: string;
13
17
  };
@@ -1,4 +1,5 @@
1
1
  import { logger } from '../../../logger';
2
+ import { getProportionalSize } from '../../../utils';
2
3
  import { imageNodeName } from '../../markdown';
3
4
  import { ImgSizeAttr } from '../../specs';
4
5
  import { IMG_MAX_HEIGHT } from './const';
@@ -11,9 +12,9 @@ export const createImageNode = (imgType, opts) => async ({ result, file }) => {
11
12
  [ImgSizeAttr.Src]: result.url,
12
13
  [ImgSizeAttr.Alt]: (_a = result.name) !== null && _a !== void 0 ? _a : file.name,
13
14
  };
14
- if (opts.needDimmensions) {
15
+ if (opts.needDimensions) {
15
16
  try {
16
- const sizes = await loadImage(file).then(getImageSize);
17
+ const sizes = await loadImage(file).then(opts.enableNewImageSizeCalculation ? getImageSizeNew : getImageSize);
17
18
  Object.assign(attrs, sizes);
18
19
  }
19
20
  catch (err) {
@@ -36,3 +37,11 @@ export async function loadImage(imgFile) {
36
37
  export function getImageSize(img) {
37
38
  return { height: String(Math.min(IMG_MAX_HEIGHT, img.height)) };
38
39
  }
40
+ export function getImageSizeNew({ width, height }) {
41
+ const size = getProportionalSize({
42
+ width,
43
+ height,
44
+ imgMaxHeight: IMG_MAX_HEIGHT,
45
+ });
46
+ return { width: String(size.width), height: String(size.height) };
47
+ }
@@ -59,7 +59,7 @@ export const VideoSpecs = (builder, opts) => {
59
59
  type: 'text/html',
60
60
  width: String(options[service].width),
61
61
  height: String(options[service].height),
62
- src: options.url(service, videoId, options),
62
+ src: options.videoUrl(service, videoId, options),
63
63
  frameborder: '0',
64
64
  webkitallowfullscreen: '',
65
65
  mozallowfullscreen: '',
@@ -1,5 +1,5 @@
1
1
  import { ExtensionAuto } from '../../../../core';
2
- import { FileUploadHandler } from '../../../../utils/upload';
2
+ import { FileUploadHandler } from '../../../../utils';
3
3
  export declare type YfmFilePasteOptions = {
4
4
  fileUploadHandler: FileUploadHandler;
5
5
  needToSetDimensionsForUploadedImages: boolean;
@@ -72,7 +72,7 @@ class YfmFilesPasteUploadProcess extends YfmFilesUploadProcessBase {
72
72
  const { schema } = this.view.state;
73
73
  if (imageType(schema)) {
74
74
  this.createImage = createImageNode(imageType(schema), {
75
- needDimmensions: opts.needToSetDimensionsForUploadedImages,
75
+ needDimensions: opts.needToSetDimensionsForUploadedImages,
76
76
  });
77
77
  }
78
78
  }
@@ -1,4 +1,4 @@
1
- export declare const i18n: <G extends "bold" | "code" | "link" | "italic" | "strike" | "underline" | "mark" | "quote" | "colorify" | "mono" | "text" | "html" | "cut" | "table" | "image" | "code_inline" | "list" | "heading" | "note" | "file" | "codeblock" | "checkbox" | "emoji" | "tabs" | "math" | "heading1" | "heading2" | "heading3" | "heading4" | "heading5" | "heading6" | "gpt" | "undo" | "redo" | "math_inline" | "math_block" | "mermaid" | "colorify__color_blue" | "colorify__color_default" | "colorify__color_gray" | "colorify__color_green" | "colorify__color_orange" | "colorify__color_red" | "colorify__color_violet" | "colorify__color_yellow" | "colorify__group_text" | "folding-heading" | "folding-heading_hint" | "hrule" | "list__action_lift" | "list__action_sink" | "list_action_disabled" | "more_action" | "olist" | "ulist", S extends string>(key: G | (string extends S ? S : never), params?: {
1
+ export declare const i18n: <G extends "bold" | "code" | "colorify" | "mono" | "link" | "italic" | "strike" | "underline" | "mark" | "quote" | "text" | "html" | "cut" | "table" | "image" | "code_inline" | "list" | "heading" | "note" | "file" | "checkbox" | "emoji" | "undo" | "redo" | "heading1" | "heading2" | "heading3" | "heading4" | "heading5" | "heading6" | "math_inline" | "math_block" | "tabs" | "mermaid" | "gpt" | "codeblock" | "math" | "colorify__color_blue" | "colorify__color_default" | "colorify__color_gray" | "colorify__color_green" | "colorify__color_orange" | "colorify__color_red" | "colorify__color_violet" | "colorify__color_yellow" | "colorify__group_text" | "folding-heading" | "folding-heading_hint" | "hrule" | "list__action_lift" | "list__action_sink" | "list_action_disabled" | "more_action" | "olist" | "ulist", S extends string>(key: G | (string extends S ? S : never), params?: {
2
2
  [key: string]: any;
3
3
  } | undefined) => S extends G ? {
4
4
  bold: string;
@@ -1,4 +1,4 @@
1
- export declare const i18n: <G extends "block" | "heading" | "codeblock" | "doc_empty" | "checkbox" | "deflist_term" | "deflist_desc" | "cut_title" | "cut_content" | "note_title" | "note_content" | "layout_cell" | "table_cell" | "select_filter", S extends string>(key: G | (string extends S ? S : never), params?: {
1
+ export declare const i18n: <G extends "block" | "heading" | "checkbox" | "doc_empty" | "codeblock" | "deflist_term" | "deflist_desc" | "cut_title" | "cut_content" | "note_title" | "note_content" | "layout_cell" | "table_cell" | "select_filter", S extends string>(key: G | (string extends S ? S : never), params?: {
2
2
  [key: string]: any;
3
3
  } | undefined) => S extends G ? {
4
4
  doc_empty: string;
@@ -1,4 +1,4 @@
1
- export declare const i18n: <G extends "remove" | "info" | "alert" | "tip" | "warning", S extends string>(key: G | (string extends S ? S : never), params?: {
1
+ export declare const i18n: <G extends "remove" | "info" | "warning" | "tip" | "alert", S extends string>(key: G | (string extends S ? S : never), params?: {
2
2
  [key: string]: any;
3
3
  } | undefined) => S extends G ? {
4
4
  info: string;
@@ -1,6 +1,7 @@
1
1
  import { autocompletion } from '@codemirror/autocomplete';
2
2
  import type { Extension, StateCommand } from '@codemirror/state';
3
3
  import { EditorView, EditorViewConfig, KeyBinding, placeholder } from '@codemirror/view';
4
+ import type { ParseInsertedUrlAsImage } from '../../bundle';
4
5
  import { EventMap } from '../../bundle/Editor';
5
6
  import { ReactRenderStorage } from '../../extensions';
6
7
  import { Receiver } from '../../utils';
@@ -18,7 +19,9 @@ export declare type CreateCodemirrorParams = {
18
19
  onScroll: (event: Event) => void;
19
20
  reactRenderer: ReactRenderStorage;
20
21
  uploadHandler?: FileUploadHandler;
21
- needImgDimms?: boolean;
22
+ parseInsertedUrlAsImage?: ParseInsertedUrlAsImage;
23
+ needImageDimensions?: boolean;
24
+ enableNewImageSizeCalculation?: boolean;
22
25
  extensions?: Extension[];
23
26
  disabledExtensions?: {
24
27
  history?: boolean;
@@ -3,9 +3,10 @@ import { defaultKeymap, history, historyKeymap, indentWithTab, insertNewlineKeep
3
3
  import { syntaxHighlighting } from '@codemirror/language';
4
4
  import { EditorView, keymap, placeholder } from '@codemirror/view';
5
5
  import { ActionName } from '../../bundle/config/action-names';
6
+ import { DataTransferType } from '../../extensions/behavior/Clipboard/utils';
6
7
  import { logger } from '../../logger';
7
8
  import { Action as A, formatter as f } from '../../shortcuts';
8
- import { insertLink, toH1, toH2, toH3, toH4, toH5, toH6, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline, wrapToCodeBlock, wrapToInlineCode, wrapToYfmCut, wrapToYfmNote, } from '../commands';
9
+ import { insertImages, insertLink, toH1, toH2, toH3, toH4, toH5, toH6, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline, wrapToCodeBlock, wrapToInlineCode, wrapToYfmCut, wrapToYfmNote, } from '../commands';
9
10
  import { FileUploadHandlerFacet } from './files-upload-facet';
10
11
  import { gravityHighlightStyle, gravityTheme } from './gravity';
11
12
  import { PairingCharactersExtension } from './pairing-chars';
@@ -13,7 +14,7 @@ import { ReactRendererFacet } from './react-facet';
13
14
  import { SearchPanelPlugin } from './search-plugin/plugin';
14
15
  import { yfmLang } from './yfm';
15
16
  export function createCodemirror(params) {
16
- const { doc, reactRenderer, onCancel, onScroll, onSubmit, onChange, onDocChange, disabledExtensions = {}, keymaps = [], receiver, yfmLangOptions, extensions: extraExtensions, placeholder: placeholderContent, autocompletion: autocompletionConfig, } = params;
17
+ const { doc, reactRenderer, onCancel, onScroll, onSubmit, onChange, onDocChange, disabledExtensions = {}, keymaps = [], receiver, yfmLangOptions, extensions: extraExtensions, placeholder: placeholderContent, autocompletion: autocompletionConfig, parseInsertedUrlAsImage, } = params;
17
18
  const extensions = [gravityTheme, placeholder(placeholderContent)];
18
19
  if (!disabledExtensions.history) {
19
20
  extensions.push(history());
@@ -63,6 +64,23 @@ export function createCodemirror(params) {
63
64
  scroll(event) {
64
65
  onScroll(event);
65
66
  },
67
+ paste(event, editor) {
68
+ var _a;
69
+ if (event.clipboardData && parseInsertedUrlAsImage) {
70
+ const { imageUrl, title } = parseInsertedUrlAsImage((_a = event.clipboardData.getData(DataTransferType.Text)) !== null && _a !== void 0 ? _a : '') || {};
71
+ if (!imageUrl) {
72
+ return;
73
+ }
74
+ event.preventDefault();
75
+ insertImages([
76
+ {
77
+ url: imageUrl,
78
+ alt: title,
79
+ title,
80
+ },
81
+ ])(editor);
82
+ }
83
+ },
66
84
  }), SearchPanelPlugin({
67
85
  anchorSelector: '.g-md-search-anchor',
68
86
  receiver,
@@ -70,7 +88,8 @@ export function createCodemirror(params) {
70
88
  if (params.uploadHandler) {
71
89
  extensions.push(FileUploadHandlerFacet.of({
72
90
  fn: params.uploadHandler,
73
- imgWithDimms: params.needImgDimms,
91
+ imageWithDimensions: params.needImageDimensions,
92
+ enableNewImageSizeCalculation: params.enableNewImageSizeCalculation,
74
93
  }));
75
94
  }
76
95
  if (extraExtensions) {
@@ -3,8 +3,10 @@ import type { FileUploadHandler } from '../../utils/upload';
3
3
  export type { FileUploadHandler };
4
4
  export declare const FileUploadHandlerFacet: Facet<{
5
5
  fn: FileUploadHandler;
6
- imgWithDimms?: boolean | undefined;
6
+ imageWithDimensions?: boolean | undefined;
7
+ enableNewImageSizeCalculation?: boolean | undefined;
7
8
  }, {
8
9
  fn: FileUploadHandler;
9
- imgWithDimms?: boolean | undefined;
10
+ imageWithDimensions?: boolean | undefined;
11
+ enableNewImageSizeCalculation?: boolean | undefined;
10
12
  }>;
@@ -1,4 +1,5 @@
1
1
  import { Decoration, ViewPlugin, WidgetType, } from '@codemirror/view';
2
+ import { getProportionalSize } from '../../../utils';
2
3
  import { FileUploadHandlerFacet } from '../files-upload-facet';
3
4
  import { ReactRendererFacet } from '../react-facet';
4
5
  import { IMG_MAX_HEIGHT, SUCCESS_UPLOAD_REMOVE_TIMEOUT } from './const';
@@ -91,7 +92,8 @@ class FileUploadPresenter {
91
92
  this.view = params.view;
92
93
  this.widget = params.widget;
93
94
  this.uploader = params.uploader;
94
- this.needDimmensionsForImages = params.needDimmensionsForImages;
95
+ this.needDimensionsForImages = params.needDimensionsForImages;
96
+ this.enableNewImageSizeCalculation = params.enableNewImageSizeCalculation;
95
97
  this.widget.setPresenter(this);
96
98
  this.run();
97
99
  }
@@ -110,21 +112,29 @@ class FileUploadPresenter {
110
112
  async formatFileMarkup(res) {
111
113
  var _a, _b;
112
114
  const fileName = (_b = (_a = res.name) !== null && _a !== void 0 ? _a : this.file.name) !== null && _b !== void 0 ? _b : '';
113
- let markup;
115
+ let markup = `![${fileName}](${res.url}`;
114
116
  if (isImageFile(this.file)) {
115
- if (this.needDimmensionsForImages) {
117
+ if (this.needDimensionsForImages) {
116
118
  try {
117
- let { height } = await getImageDimensions(this.file);
118
- height = Math.min(height, IMG_MAX_HEIGHT);
119
- markup = `![${fileName}](${res.url} =x${height})`;
119
+ const fileSize = await getImageDimensions(this.file);
120
+ if (this.enableNewImageSizeCalculation) {
121
+ const { width, height } = getProportionalSize({
122
+ width: fileSize.width,
123
+ height: fileSize.height,
124
+ imgMaxHeight: IMG_MAX_HEIGHT,
125
+ });
126
+ markup += ` =${width}x${height}`;
127
+ }
128
+ else {
129
+ const height = Math.min(fileSize.height, IMG_MAX_HEIGHT);
130
+ markup += ` =x${height}`;
131
+ }
120
132
  }
121
133
  catch (err) {
122
- markup = `![${fileName}](${res.url})`;
134
+ console.error(err);
123
135
  }
124
136
  }
125
- else {
126
- markup = `![${fileName}](${res.url})`;
127
- }
137
+ markup += `)`;
128
138
  }
129
139
  else {
130
140
  markup = `{% file src="${res.url}" name="${fileName.replace('"', '')}" %}`;
@@ -150,7 +160,8 @@ export const FilesUploadPlugin = ViewPlugin.fromClass(class {
150
160
  file,
151
161
  view: this.view,
152
162
  uploader: uploadFacet.fn,
153
- needDimmensionsForImages: Boolean(uploadFacet.imgWithDimms),
163
+ needDimensionsForImages: Boolean(uploadFacet.imageWithDimensions),
164
+ enableNewImageSizeCalculation: Boolean(uploadFacet.enableNewImageSizeCalculation),
154
165
  widget: new FileUploadWidget(uniqueId('__file_widget_id')),
155
166
  });
156
167
  return Decoration.widget({
@@ -1,4 +1,4 @@
1
- import { isFilesFromHtml, isFilesOnly } from '../../../utils/clipboard';
1
+ import { isFilesFromHtml, isFilesOnly } from '../../../utils';
2
2
  export { uniqueId } from '../../../lodash';
3
3
  export { isImageFile } from '../../../utils/clipboard';
4
4
  export async function getImageDimensions(imgFile) {
@@ -8,7 +8,7 @@ export declare const customTags: {
8
8
  };
9
9
  export declare type YfmNoteType = 'info' | 'tip' | 'warning' | 'alert';
10
10
  export declare const yfmNoteTypes: readonly YfmNoteType[];
11
- export declare const yfmNoteSnippetTemplate: (type: YfmNoteType) => "{% note info %}\n\n#{}\n\n{% endnote %}\n\n" | "{% note alert %}\n\n#{}\n\n{% endnote %}\n\n" | "{% note tip %}\n\n#{}\n\n{% endnote %}\n\n" | "{% note warning %}\n\n#{}\n\n{% endnote %}\n\n";
11
+ export declare const yfmNoteSnippetTemplate: (type: YfmNoteType) => "{% note info %}\n\n#{}\n\n{% endnote %}\n\n" | "{% note warning %}\n\n#{}\n\n{% endnote %}\n\n" | "{% note tip %}\n\n#{}\n\n{% endnote %}\n\n" | "{% note alert %}\n\n#{}\n\n{% endnote %}\n\n";
12
12
  export declare const yfmNoteSnippets: Record<YfmNoteType, ReturnType<typeof snippet>>;
13
13
  export declare const yfmCutSnippetTemplate = "{% cut \"#{title}\" %}\n\n#{}\n\n{% endcut %}\n\n";
14
14
  export declare const yfmCutSnippet: (editor: {
@@ -21,9 +21,15 @@ export function insertImages(images) {
21
21
  return ({ state, dispatch }) => {
22
22
  const markup = images
23
23
  .map(({ title, url, alt, width, height }) => {
24
- const titleStr = title ? ` "${title}"` : '';
25
- const sizeStr = (width !== null && width !== void 0 ? width : height) ? ` =${width !== null && width !== void 0 ? width : ''}x${height !== null && height !== void 0 ? height : ''}` : '';
26
- return `![${alt !== null && alt !== void 0 ? alt : ''}](${url !== null && url !== void 0 ? url : ''}${titleStr}${sizeStr})`;
24
+ let result = `![${alt !== null && alt !== void 0 ? alt : ''}](${url !== null && url !== void 0 ? url : ''}`;
25
+ if (title) {
26
+ result += ` "${title}`;
27
+ }
28
+ if (width !== undefined || height !== undefined) {
29
+ result += ` =${width !== null && width !== void 0 ? width : ''}x${height !== null && height !== void 0 ? height : ''}`;
30
+ }
31
+ result += ')';
32
+ return result;
27
33
  })
28
34
  .join(' ');
29
35
  const tr = state.changeByRange((range) => {
@@ -1,5 +1,5 @@
1
1
  import type { Extension, ExtensionAuto } from '../core';
2
- import { BlockquoteOptions, BoldOptions, BreaksOptions, CodeBlockOptions, CodeOptions, HeadingOptions, ItalicOptions, LinkOptions, ListsOptions } from '../extensions/markdown';
2
+ import { BlockquoteOptions, BoldOptions, BreaksOptions, CodeBlockOptions, CodeOptions, HeadingOptions, ImageOptions, ItalicOptions, LinkOptions, ListsOptions } from '../extensions/markdown';
3
3
  import { ZeroPresetOptions } from './zero';
4
4
  export declare type CommonMarkPresetOptions = ZeroPresetOptions & {
5
5
  bold?: BoldOptions;
@@ -8,7 +8,7 @@ export declare type CommonMarkPresetOptions = ZeroPresetOptions & {
8
8
  lists?: ListsOptions;
9
9
  italic?: ItalicOptions;
10
10
  breaks?: BreaksOptions;
11
- image?: false | Extension;
11
+ image?: false | Extension | ImageOptions;
12
12
  codeBlock?: CodeBlockOptions;
13
13
  blockquote?: BlockquoteOptions;
14
14
  heading?: false | Extension | HeadingOptions;
@@ -16,7 +16,7 @@ export const CommonMarkPreset = (builder, opts) => {
16
16
  .use(CodeBlock, (_g = opts.codeBlock) !== null && _g !== void 0 ? _g : {})
17
17
  .use(Blockquote, (_h = opts.blockquote) !== null && _h !== void 0 ? _h : {});
18
18
  if (opts.image !== false) {
19
- builder.use(isFunction(opts.image) ? opts.image : Image);
19
+ builder.use(isFunction(opts.image) ? opts.image : Image, isFunction(opts.image) ? undefined : opts.image);
20
20
  }
21
21
  if (opts.heading !== false) {
22
22
  if (isFunction(opts.heading))
@@ -0,0 +1,10 @@
1
+ declare type GetProportionalSizeParams = {
2
+ width: number;
3
+ height: number;
4
+ imgMaxHeight: number;
5
+ };
6
+ export declare function getProportionalSize({ width: _width, height: _height, imgMaxHeight, }: GetProportionalSizeParams): {
7
+ width: number;
8
+ height: number;
9
+ };
10
+ export {};
@@ -0,0 +1,10 @@
1
+ export function getProportionalSize({ width: _width, height: _height, imgMaxHeight, }) {
2
+ let width = _width;
3
+ let height = _height;
4
+ const ratio = width / height;
5
+ if (height > imgMaxHeight) {
6
+ height = imgMaxHeight;
7
+ width = Math.round(height * ratio);
8
+ }
9
+ return { width, height };
10
+ }
@@ -5,7 +5,7 @@ export * from './clipboard';
5
5
  export * from './ecapeRegexp';
6
6
  export * from './event-emitter';
7
7
  export * from './helpers';
8
- export { markInputRule, nodeInputRule, inlineNodeInputRule, textblockTypeInputRule, wrappingInputRule, } from './inputrules';
8
+ export * from './inputrules';
9
9
  export * from './keymap';
10
10
  export * from './marks';
11
11
  export * from './node-children';
@@ -18,3 +18,4 @@ export * from './selection';
18
18
  export * from './serialize-for-clipboard';
19
19
  export * from './sync-scroll';
20
20
  export * from './upload';
21
+ export * from './get-proportional-size';
@@ -5,7 +5,7 @@ export * from './clipboard';
5
5
  export * from './ecapeRegexp';
6
6
  export * from './event-emitter';
7
7
  export * from './helpers';
8
- export { markInputRule, nodeInputRule, inlineNodeInputRule, textblockTypeInputRule, wrappingInputRule, } from './inputrules';
8
+ export * from './inputrules';
9
9
  export * from './keymap';
10
10
  export * from './marks';
11
11
  export * from './node-children';
@@ -18,3 +18,4 @@ export * from './selection';
18
18
  export * from './serialize-for-clipboard';
19
19
  export * from './sync-scroll';
20
20
  export * from './upload';
21
+ export * from './get-proportional-size';
@@ -1,2 +1,2 @@
1
1
  /** During build process, the current version will be injected here */
2
- export const VERSION = typeof '14.0.2' !== 'undefined' ? '14.0.2' : 'unknown';
2
+ export const VERSION = typeof '14.2.0' !== 'undefined' ? '14.2.0' : 'unknown';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/markdown-editor",
3
- "version": "14.0.2",
3
+ "version": "14.2.0",
4
4
  "description": "Markdown wysiwyg and markup editor",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -19,8 +19,8 @@
19
19
  "clean": "gulp clean",
20
20
  "build": "gulp",
21
21
  "typecheck": "tsc -p tsconfig.json --noEmit",
22
- "storybook:start": "TS_NODE_PROJECT=.storybook/tsconfig.json sb dev -p 8888 -c .storybook",
23
- "storybook:build": "TS_NODE_PROJECT=.storybook/tsconfig.json sb build -c .storybook -o storybook-static",
22
+ "storybook:start": "TS_NODE_PROJECT=.storybook/tsconfig.json storybook dev -p 8888 -c .storybook",
23
+ "storybook:build": "TS_NODE_PROJECT=.storybook/tsconfig.json storybook build -c .storybook -o storybook-static",
24
24
  "lint": "run-p -cs lint:*",
25
25
  "lint:js": "eslint \"{src,demo}/**/*.{js,jsx,ts,tsx}\"",
26
26
  "lint:styles": "stylelint \"{src,demo}/**/*.{css,scss}\"",
@@ -170,6 +170,7 @@
170
170
  "@gravity-ui/icons": "^2.10.0",
171
171
  "@lezer/highlight": "~1.2.1",
172
172
  "@lezer/markdown": "~1.3.1",
173
+ "@storybook/react": "8.4.1",
173
174
  "@types/is-number": "^7.0.1",
174
175
  "@types/markdown-it": "^12.2.3",
175
176
  "base64-arraybuffer": "1.0.2",
@@ -206,17 +207,19 @@
206
207
  "@diplodoc/latex-extension": "1.0.3",
207
208
  "@diplodoc/mermaid-extension": "1.2.1",
208
209
  "@diplodoc/tabs-extension": "^3.5.1",
209
- "@diplodoc/transform": "^4.33.0",
210
+ "@diplodoc/transform": "^4.36.0",
210
211
  "@gravity-ui/components": "3.0.0",
211
212
  "@gravity-ui/eslint-config": "3.1.1",
212
213
  "@gravity-ui/prettier-config": "1.1.0",
213
214
  "@gravity-ui/stylelint-config": "4.0.1",
214
215
  "@gravity-ui/tsconfig": "1.0.0",
215
216
  "@gravity-ui/uikit": "6.11.0",
216
- "@storybook/addon-essentials": "^7.1.1",
217
- "@storybook/cli": "^7.1.1",
217
+ "@storybook/addon-essentials": "^8.4.1",
218
+ "@storybook/addon-webpack5-compiler-babel": "3.0.3",
219
+ "@storybook/cli": "^8.4.1",
218
220
  "@storybook/preset-scss": "1.0.3",
219
- "@storybook/react-webpack5": "^7.1.1",
221
+ "@storybook/react-webpack5": "^8.4.1",
222
+ "@storybook/theming": "^8.4.1",
220
223
  "@types/gulp": "4.0.9",
221
224
  "@types/gulp-sass": "5.0.0",
222
225
  "@types/jest": "^27.0.3",