@gravity-ui/markdown-editor 13.18.0 → 13.18.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/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ ![Markdown Editor](https://github.com/user-attachments/assets/40be2902-a683-4167-bd8d-ffd8bff26e69)
2
+
1
3
  # @gravity-ui/markdown-editor · [![npm package](https://img.shields.io/npm/v/@gravity-ui/markdown-editor)](https://www.npmjs.com/package/@gravity-ui/markdown-editor) [![CI](https://img.shields.io/github/actions/workflow/status/gravity-ui/markdown-editor/ci.yml?branch=main&label=CI)](https://github.com/gravity-ui/markdown-editor/actions/workflows/ci.yml?query=branch:main) [![Release](https://img.shields.io/github/actions/workflow/status/gravity-ui/markdown-editor/release.yml?branch=main&label=Release)](https://github.com/gravity-ui/markdown-editor/actions/workflows/release.yml?query=branch:main) [![storybook](https://img.shields.io/badge/Storybook-deployed-ff4685)](https://preview.gravity-ui.com/md-editor/)
2
4
 
3
5
  ## Markdown wysiwyg and markup editor
@@ -56,7 +58,7 @@ Read more:
56
58
  - [How to add Latex extension](docs/how-to-connect-latex-extension.md)
57
59
  - [How to add Mermaid extension](docs/how-to-connect-mermaid-extension.md)
58
60
  - [How to write extension](docs/how-to-create-extension.md)
59
- - [How to add gpt extension](docs/how-to-connect-gpt-extensions.md)
61
+ - [How to add GPT extension](docs/how-to-connect-gpt-extensions.md)
60
62
 
61
63
 
62
64
  ### i18n
@@ -92,7 +92,10 @@ const clipboard = ({ textParser, mdParser, serializer, pasteFileHandler, }) => {
92
92
  const codeType = (0, code_1.isInsideCode)(view.state);
93
93
  if (codeType) {
94
94
  const schema = view.state.schema;
95
- view.dispatch((0, core_1.trackTransactionMetrics)(view.state.tr.replaceSelectionWith(schema.text(codeType === 'inline' ? data.trim() : data)), 'paste', { clipboardDataFormat: dataFormat, code: codeType }));
95
+ const insideCodeData = e.clipboardData.getData(utils_1.DataTransferType.Text);
96
+ view.dispatch((0, core_1.trackTransactionMetrics)(view.state.tr.replaceSelectionWith(schema.text(codeType === 'inline'
97
+ ? insideCodeData.trim()
98
+ : insideCodeData)), 'paste', { clipboardDataFormat: utils_1.DataTransferType.Text, code: codeType }));
96
99
  isPasteHandled = true;
97
100
  }
98
101
  else {
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LoadingScreen = exports.cnGptDialogLoadingScreen = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importDefault(require("react"));
6
- const classname_1 = require("@bem-react/classname");
7
6
  const uikit_1 = require("@gravity-ui/uikit");
7
+ const classname_1 = require("../../../../../classname");
8
8
  const loading_1 = require("../../../../../i18n/gpt/loading");
9
9
  const GPTLoading_1 = tslib_1.__importDefault(require("../../../../../icons/GPTLoading"));
10
10
  const IconRefuge_1 = require("../../IconRefuge/IconRefuge");
@@ -13,7 +13,7 @@ exports.cnGptDialogPresetList = (0, classname_1.cn)('gpt-dialog-preset-list');
13
13
  const PresetItem = ({ preset, onPresetClick, disablePromptPresets, hotKey }) => {
14
14
  (0, useGptHotKeys_1.useGptHotKeys)(hotKey, () => {
15
15
  onPresetClick(preset.data);
16
- }, { enableOnFormTags: true });
16
+ }, { enableOnFormTags: true, enableOnContentEditable: true });
17
17
  return (react_1.default.createElement(uikit_1.ActionTooltip, { title: preset.display, hotkey: hotKey },
18
18
  react_1.default.createElement(uikit_1.Button, { className: (0, exports.cnGptDialogPresetList)('preset'), view: "normal", size: "m", disabled: disablePromptPresets, onClick: () => onPresetClick(preset.data) }, preset.display)));
19
19
  };
@@ -150,10 +150,6 @@ class GptWidgetDecoView {
150
150
  }
151
151
  exports.GptWidgetDecoView = GptWidgetDecoView;
152
152
  function Widget({ markup, anchorRef, answerRender, promptPresets, disablePromptPresets, customPromptPlaceholder, disabledPromptPlaceholder, onCustomPromptApply, onApplyResult, onPromptPresetClick, onTryAgain, onLike, onDislike, onClose, onUpdate, container, gptAlertProps, }) {
153
- (0, react_1.useEffect)(() => {
154
- // rerender the popup
155
- window.dispatchEvent(new CustomEvent('scroll'));
156
- }, [anchorRef]);
157
153
  (0, react_use_1.useMount)(() => {
158
154
  if ((anchorRef === null || anchorRef === void 0 ? void 0 : anchorRef.current) && 'scrollIntoView' in anchorRef.current) {
159
155
  anchorRef.current.scrollIntoView({
@@ -166,6 +162,6 @@ function Widget({ markup, anchorRef, answerRender, promptPresets, disablePromptP
166
162
  onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate(result);
167
163
  }, [onUpdate]);
168
164
  return (react_1.default.createElement(react_1.default.Fragment, null,
169
- react_1.default.createElement(uikit_1.Popup, { className: (0, exports.cnGptPopup)(), contentClassName: (0, exports.cnGptPopup)('content'), open: true, anchorRef: anchorRef, placement: constants_1.gptPopupPlacement, onOutsideClick: onClose, focusTrap: true, strategy: "absolute", container: container, onEscapeKeyDown: onClose },
165
+ react_1.default.createElement(uikit_1.Popup, { className: (0, exports.cnGptPopup)(), contentClassName: (0, exports.cnGptPopup)('content'), open: true, anchorRef: anchorRef, placement: constants_1.gptPopupPlacement, onOutsideClick: onClose, focusTrap: true, autoFocus: !onCustomPromptApply && true, strategy: "absolute", container: container, onEscapeKeyDown: onClose },
170
166
  react_1.default.createElement(GptDialog_1.GptDialog, { markup: markup, answerRender: answerRender, promptPresets: promptPresets, disablePromptPresets: disablePromptPresets, customPromptPlaceholder: customPromptPlaceholder, disabledPromptPlaceholder: disabledPromptPlaceholder, onApplyResult: onApplyResult, onCustomPromptApply: onCustomPromptApply, onPromptPresetClick: onPromptPresetClick, onTryAgain: onTryAgain, onLike: onLike, onDislike: onDislike, onClose: onClose, onUpdate: handleUpdate, gptAlertProps: gptAlertProps }))));
171
167
  }
@@ -32,6 +32,13 @@ const useGpt = ({ markup, promptPresets, onCustomPromptApply, onPromptPresetClic
32
32
  }
33
33
  finally {
34
34
  setLoading(false);
35
+ setTimeout(() => {
36
+ // hack for popup rerender
37
+ // When a lot of text is entered into the GPT popup,
38
+ // it expands and goes beyond the boundaries. However,
39
+ // the popup does not handle height changes.
40
+ window.dispatchEvent(new CustomEvent('scroll'));
41
+ });
35
42
  onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate(result);
36
43
  }
37
44
  }, [onUpdate]);
@@ -51,9 +51,14 @@ const useNodeResizing = ({ width, height, onResize, ref, delay = RESIZE_DELAY, t
51
51
  const newHeight = (startHeight / startWidth) * newWidth;
52
52
  setCurrentWidth(newWidth);
53
53
  setCurrentHeight(newHeight);
54
+ // If neither width nor height are provided, the width is set automatically.
55
+ const shouldSetWidth = !initialWidth &&
56
+ initialWidth !== 0 &&
57
+ !(initialWidth === null && initialHeight === null);
58
+ const shouldSetHeight = !initialHeight && initialHeight !== 0;
54
59
  onResize === null || onResize === void 0 ? void 0 : onResize({
55
- width: !initialWidth && initialWidth !== 0 ? undefined : newWidth,
56
- height: !initialHeight && initialHeight !== 0 ? undefined : newHeight,
60
+ width: shouldSetWidth ? undefined : newWidth,
61
+ height: shouldSetHeight ? undefined : newHeight,
57
62
  });
58
63
  }
59
64
  });
@@ -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 '13.18.0' !== 'undefined' ? '13.18.0' : 'unknown';
5
+ exports.VERSION = typeof '13.18.1' !== 'undefined' ? '13.18.1' : 'unknown';
@@ -89,7 +89,10 @@ export const clipboard = ({ textParser, mdParser, serializer, pasteFileHandler,
89
89
  const codeType = isInsideCode(view.state);
90
90
  if (codeType) {
91
91
  const schema = view.state.schema;
92
- view.dispatch(trackTransactionMetrics(view.state.tr.replaceSelectionWith(schema.text(codeType === 'inline' ? data.trim() : data)), 'paste', { clipboardDataFormat: dataFormat, code: codeType }));
92
+ const insideCodeData = e.clipboardData.getData(DataTransferType.Text);
93
+ view.dispatch(trackTransactionMetrics(view.state.tr.replaceSelectionWith(schema.text(codeType === 'inline'
94
+ ? insideCodeData.trim()
95
+ : insideCodeData)), 'paste', { clipboardDataFormat: DataTransferType.Text, code: codeType }));
93
96
  isPasteHandled = true;
94
97
  }
95
98
  else {
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import { cn } from '@bem-react/classname';
3
2
  import { Skeleton } from '@gravity-ui/uikit';
3
+ import { cn } from '../../../../../classname';
4
4
  import { i18n } from '../../../../../i18n/gpt/loading';
5
5
  import GPTLoading from '../../../../../icons/GPTLoading';
6
6
  import { IconRefuge } from '../../IconRefuge/IconRefuge';
@@ -10,7 +10,7 @@ export const cnGptDialogPresetList = cn('gpt-dialog-preset-list');
10
10
  const PresetItem = ({ preset, onPresetClick, disablePromptPresets, hotKey }) => {
11
11
  useGptHotKeys(hotKey, () => {
12
12
  onPresetClick(preset.data);
13
- }, { enableOnFormTags: true });
13
+ }, { enableOnFormTags: true, enableOnContentEditable: true });
14
14
  return (React.createElement(ActionTooltip, { title: preset.display, hotkey: hotKey },
15
15
  React.createElement(Button, { className: cnGptDialogPresetList('preset'), view: "normal", size: "m", disabled: disablePromptPresets, onClick: () => onPresetClick(preset.data) }, preset.display)));
16
16
  };
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useEffect } from 'react';
1
+ import React, { useCallback } from 'react';
2
2
  import { Popup } from '@gravity-ui/uikit';
3
3
  import { Slice } from 'prosemirror-model';
4
4
  import { TextSelection } from 'prosemirror-state';
@@ -146,10 +146,6 @@ export class GptWidgetDecoView {
146
146
  }
147
147
  }
148
148
  function Widget({ markup, anchorRef, answerRender, promptPresets, disablePromptPresets, customPromptPlaceholder, disabledPromptPlaceholder, onCustomPromptApply, onApplyResult, onPromptPresetClick, onTryAgain, onLike, onDislike, onClose, onUpdate, container, gptAlertProps, }) {
149
- useEffect(() => {
150
- // rerender the popup
151
- window.dispatchEvent(new CustomEvent('scroll'));
152
- }, [anchorRef]);
153
149
  useMount(() => {
154
150
  if ((anchorRef === null || anchorRef === void 0 ? void 0 : anchorRef.current) && 'scrollIntoView' in anchorRef.current) {
155
151
  anchorRef.current.scrollIntoView({
@@ -162,6 +158,6 @@ function Widget({ markup, anchorRef, answerRender, promptPresets, disablePromptP
162
158
  onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate(result);
163
159
  }, [onUpdate]);
164
160
  return (React.createElement(React.Fragment, null,
165
- React.createElement(Popup, { className: cnGptPopup(), contentClassName: cnGptPopup('content'), open: true, anchorRef: anchorRef, placement: gptPopupPlacement, onOutsideClick: onClose, focusTrap: true, strategy: "absolute", container: container, onEscapeKeyDown: onClose },
161
+ React.createElement(Popup, { className: cnGptPopup(), contentClassName: cnGptPopup('content'), open: true, anchorRef: anchorRef, placement: gptPopupPlacement, onOutsideClick: onClose, focusTrap: true, autoFocus: !onCustomPromptApply && true, strategy: "absolute", container: container, onEscapeKeyDown: onClose },
166
162
  React.createElement(GptDialog, { markup: markup, answerRender: answerRender, promptPresets: promptPresets, disablePromptPresets: disablePromptPresets, customPromptPlaceholder: customPromptPlaceholder, disabledPromptPlaceholder: disabledPromptPlaceholder, onApplyResult: onApplyResult, onCustomPromptApply: onCustomPromptApply, onPromptPresetClick: onPromptPresetClick, onTryAgain: onTryAgain, onLike: onLike, onDislike: onDislike, onClose: onClose, onUpdate: handleUpdate, gptAlertProps: gptAlertProps }))));
167
163
  }
@@ -29,6 +29,13 @@ export const useGpt = ({ markup, promptPresets, onCustomPromptApply, onPromptPre
29
29
  }
30
30
  finally {
31
31
  setLoading(false);
32
+ setTimeout(() => {
33
+ // hack for popup rerender
34
+ // When a lot of text is entered into the GPT popup,
35
+ // it expands and goes beyond the boundaries. However,
36
+ // the popup does not handle height changes.
37
+ window.dispatchEvent(new CustomEvent('scroll'));
38
+ });
32
39
  onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate(result);
33
40
  }
34
41
  }, [onUpdate]);
@@ -47,9 +47,14 @@ export const useNodeResizing = ({ width, height, onResize, ref, delay = RESIZE_D
47
47
  const newHeight = (startHeight / startWidth) * newWidth;
48
48
  setCurrentWidth(newWidth);
49
49
  setCurrentHeight(newHeight);
50
+ // If neither width nor height are provided, the width is set automatically.
51
+ const shouldSetWidth = !initialWidth &&
52
+ initialWidth !== 0 &&
53
+ !(initialWidth === null && initialHeight === null);
54
+ const shouldSetHeight = !initialHeight && initialHeight !== 0;
50
55
  onResize === null || onResize === void 0 ? void 0 : onResize({
51
- width: !initialWidth && initialWidth !== 0 ? undefined : newWidth,
52
- height: !initialHeight && initialHeight !== 0 ? undefined : newHeight,
56
+ width: shouldSetWidth ? undefined : newWidth,
57
+ height: shouldSetHeight ? undefined : newHeight,
53
58
  });
54
59
  }
55
60
  });
@@ -1,2 +1,2 @@
1
1
  /** During build process, the current version will be injected here */
2
- export const VERSION = typeof '13.18.0' !== 'undefined' ? '13.18.0' : 'unknown';
2
+ export const VERSION = typeof '13.18.1' !== 'undefined' ? '13.18.1' : 'unknown';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/markdown-editor",
3
- "version": "13.18.0",
3
+ "version": "13.18.1",
4
4
  "description": "Markdown wysiwyg and markup editor",
5
5
  "license": "MIT",
6
6
  "repository": {