@skbkontur/markdown 2.5.8-alpha.1 → 2.5.8-alpha.10

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/index.d.ts CHANGED
@@ -2,6 +2,6 @@ export { Markdown, MarkdownProps } from './src/Markdown/Markdown';
2
2
  export { MarkdownCombination } from './src/MarkdownCombination/MarkdownCombination';
3
3
  export { markdownHelpItems, markdownHelpFiles, markdownHelpLists, markdownHelpOther, } from './src/Markdown/MarkdownHelpItems';
4
4
  export { MarkdownViewer } from './src/MarkdownViewer/MarkdownViewer';
5
- export { MarkdownApi, RefItem, User, Token, HorizontalPaddings, ViewMode, HideActionsOptions, AIMethod, } from '././src/Markdown/types';
5
+ export { MarkdownApi, RefItem, User, Token, HorizontalPaddings, ViewMode, HideActionsOptions, AIMethod, AIApi, } from '././src/Markdown/types';
6
6
  export { ThemeMode, ColorScheme } from './src/styles/types';
7
7
  export { MarkdownTheme, MarkdownThemeProvider, MarkdownThemeConsumer, MarkdownThemeContext } from './src/styles/theme';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skbkontur/markdown",
3
- "version": "2.5.8-alpha.1",
3
+ "version": "2.5.8-alpha.10",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"
@@ -1,11 +1,9 @@
1
1
  import { FC, ReactNode } from 'react';
2
2
  import { MarkdownEditorProps } from './MarkdownEditor';
3
- import { AIMethod, HideActionsOptions, HorizontalPaddings, MarkdownApi, ViewMode } from './types';
3
+ import { HideActionsOptions, HorizontalPaddings, MarkdownApi, ViewMode } from './types';
4
4
  export interface MarkdownProps extends MarkdownEditorProps {
5
5
  /** Методы апи для загрузки/скачивания файлов, меншена, ИИ */
6
6
  api?: MarkdownApi;
7
- /** Доступные методы ИИ апи */
8
- availableAIMethods?: AIMethod[];
9
7
  /** Режим прозрачной рамки у Textarea */
10
8
  borderless?: boolean;
11
9
  /** Url апи для файлов */
@@ -43,8 +43,7 @@ import { ThemeProvider } from '../styles/styled-components';
43
43
  import { DEFAULT_MARKDOWN_THEME, MarkdownThemeConsumer } from '../styles/theme';
44
44
  export var Markdown = function (props) {
45
45
  var _a;
46
- var availableAIMethods = props.availableAIMethods, panelHorizontalPadding = props.panelHorizontalPadding, onClick = props.onClick, onChange = props.onChange, onSelect = props.onSelect, markdownViewer = props.markdownViewer, renderFilesValidation = props.renderFilesValidation, fileApiUrl = props.fileApiUrl, profileUrl = props.profileUrl, api = props.api, borderless = props.borderless, showActionHints = props.showActionHints, showShortKeys = props.showShortKeys, _b = props.showShotKeys, showShotKeys = _b === void 0 ? true : _b, hideActionsOptions = props.hideActionsOptions, onChangeViewMode = props.onChangeViewMode, textareaProps = __rest(props, ["availableAIMethods", "panelHorizontalPadding", "onClick", "onChange", "onSelect", "markdownViewer", "renderFilesValidation", "fileApiUrl", "profileUrl", "api", "borderless", "showActionHints", "showShortKeys", "showShotKeys", "hideActionsOptions", "onChangeViewMode"]);
47
- var textareaRef = useRef(null);
46
+ var panelHorizontalPadding = props.panelHorizontalPadding, onClick = props.onClick, onChange = props.onChange, onSelect = props.onSelect, markdownViewer = props.markdownViewer, renderFilesValidation = props.renderFilesValidation, fileApiUrl = props.fileApiUrl, profileUrl = props.profileUrl, api = props.api, borderless = props.borderless, showActionHints = props.showActionHints, showShortKeys = props.showShortKeys, _b = props.showShotKeys, showShotKeys = _b === void 0 ? true : _b, hideActionsOptions = props.hideActionsOptions, onChangeViewMode = props.onChangeViewMode, textareaProps = __rest(props, ["panelHorizontalPadding", "onClick", "onChange", "onSelect", "markdownViewer", "renderFilesValidation", "fileApiUrl", "profileUrl", "api", "borderless", "showActionHints", "showShortKeys", "showShotKeys", "hideActionsOptions", "onChangeViewMode"]);
48
47
  var _c = useState(), mention = _c[0], setMention = _c[1];
49
48
  var _d = useState(ViewMode.Edit), viewMode = _d[0], setViewMode = _d[1];
50
49
  var _e = useState(false), fullscreen = _e[0], setFullScreen = _e[1];
@@ -52,6 +51,8 @@ export var Markdown = function (props) {
52
51
  var _g = useState(), selectionStart = _g[0], setSelectionStart = _g[1];
53
52
  var _h = useState(), selectionEnd = _h[0], setSelectionEnd = _h[1];
54
53
  var guid = useRef(new Guid().generate()).current;
54
+ var textareaRef = useRef(null);
55
+ var textareaNode = getTextareaNode();
55
56
  var isEditMode = viewMode !== ViewMode.Preview;
56
57
  var width = fullscreen || !textareaProps.width ? '100%' : textareaProps.width;
57
58
  var _j = useResponsiveLayout({
@@ -65,9 +66,9 @@ export var Markdown = function (props) {
65
66
  useListenTextareaScroll(resetMention, textareaRef.current);
66
67
  var fullscreenTextareaPadding = useFullscreenHorizontalPadding(fullscreen, viewMode, initialWidth);
67
68
  useLayoutEffect(function () {
68
- var _a;
69
- var textareaNode = (_a = textareaRef.current) === null || _a === void 0 ? void 0 : _a.node;
70
- setInitialWidth(textareaNode.clientWidth);
69
+ var textareaNode = getTextareaNode();
70
+ if (textareaNode)
71
+ setInitialWidth(textareaNode.clientWidth);
71
72
  }, []);
72
73
  useEffect(function () {
73
74
  if (fullscreen && isSplitViewAvailable)
@@ -80,23 +81,31 @@ export var Markdown = function (props) {
80
81
  setFullScreen(false);
81
82
  }, [isMobile]);
82
83
  useEffect(function () {
83
- var _a;
84
84
  if (fullscreen && isEditMode && textareaRef) {
85
- var textareaNode = (_a = textareaRef.current) === null || _a === void 0 ? void 0 : _a.node;
86
- if (textareaNode) {
87
- textareaNode.focus();
88
- textareaNode.selectionStart = selectionStart !== null && selectionStart !== void 0 ? selectionStart : 0;
89
- textareaNode.selectionEnd = selectionEnd !== null && selectionEnd !== void 0 ? selectionEnd : 0;
85
+ var textareaNode_1 = getTextareaNode();
86
+ if (textareaNode_1) {
87
+ textareaNode_1.focus();
88
+ textareaNode_1.selectionStart = selectionStart !== null && selectionStart !== void 0 ? selectionStart : 0;
89
+ textareaNode_1.selectionEnd = selectionEnd !== null && selectionEnd !== void 0 ? selectionEnd : 0;
90
90
  }
91
91
  }
92
92
  }, [fullscreen, isEditMode, selectionEnd, selectionStart, textareaRef]);
93
+ useEffect(function () {
94
+ var handleSelectionChange = function () {
95
+ var textareaNode = getTextareaNode();
96
+ setSelectionStart(textareaNode === null || textareaNode === void 0 ? void 0 : textareaNode.selectionStart);
97
+ setSelectionEnd(textareaNode === null || textareaNode === void 0 ? void 0 : textareaNode.selectionEnd);
98
+ };
99
+ document.addEventListener('selectionchange', handleSelectionChange);
100
+ return function () { return document.removeEventListener('selectionchange', handleSelectionChange); };
101
+ }, []);
93
102
  var horizontalPaddings = {
94
103
  panelPadding: panelHorizontalPadding,
95
104
  fullscreenPadding: fullscreenTextareaPadding,
96
105
  };
97
106
  var content = (React.createElement(Foco, { component: "div", onClickOutside: resetStates },
98
107
  React.createElement(Wrapper, __assign({}, getRootProps()),
99
- !(hideActionsOptions === null || hideActionsOptions === void 0 ? void 0 : hideActionsOptions.allActions) && (React.createElement(MarkdownActions, { showActionHints: showActionHints !== undefined ? showActionHints : showShotKeys, showShortKeys: showShortKeys !== undefined ? showShortKeys : showShotKeys, textAreaRef: textareaRef, width: width, viewMode: viewMode, loadingFile: requestStatus === RequestStatus.isFetching, fullscreen: fullscreen, selectionStart: selectionStart, selectionEnd: selectionEnd, horizontalPaddings: horizontalPaddings, hideOptions: hideActionsOptions, hasFilesApi: !!(api === null || api === void 0 ? void 0 : api.fileDownloadApi) && !!(api === null || api === void 0 ? void 0 : api.fileUploadApi), isSplitViewAvailable: isSplitViewAvailable, disableFullscreen: isMobile, availableAIMethods: availableAIMethods, AIApi: api === null || api === void 0 ? void 0 : api.AIApi, onOpenFileDialog: open, onChangeViewMode: handleChangeViewMode, onClickFullscreen: handleClickFullscreen, onSelectEmoji: onSelectEmoji })),
108
+ !(hideActionsOptions === null || hideActionsOptions === void 0 ? void 0 : hideActionsOptions.allActions) && (React.createElement(MarkdownActions, { showActionHints: showActionHints !== undefined ? showActionHints : showShotKeys, showShortKeys: showShortKeys !== undefined ? showShortKeys : showShotKeys, textAreaRef: textareaRef, width: width, viewMode: viewMode, loadingFile: requestStatus === RequestStatus.isFetching, fullscreen: fullscreen, selectionStart: selectionStart, selectionEnd: selectionEnd, horizontalPaddings: horizontalPaddings, hideOptions: hideActionsOptions, hasFilesApi: !!(api === null || api === void 0 ? void 0 : api.fileDownloadApi) && !!(api === null || api === void 0 ? void 0 : api.fileUploadApi), isSplitViewAvailable: isSplitViewAvailable, disableFullscreen: isMobile, AIApi: api === null || api === void 0 ? void 0 : api.AIApi, onOpenFileDialog: open, onChangeViewMode: handleChangeViewMode, onClickFullscreen: handleClickFullscreen, onSelectEmoji: onSelectEmoji })),
100
109
  isEditMode && error && (api === null || api === void 0 ? void 0 : api.getUsersApi) && (renderFilesValidation === null || renderFilesValidation === void 0 ? void 0 : renderFilesValidation(horizontalPaddings, onResetError)),
101
110
  fullscreen && viewMode === ViewMode.Split && !fullscreenTextareaPadding && (React.createElement(SplitViewContainer, null,
102
111
  React.createElement(SplitViewEditContainer, null, renderEditContainer()),
@@ -122,7 +131,7 @@ export var Markdown = function (props) {
122
131
  return (React.createElement(MarkdownEditorBlock, null,
123
132
  React.createElement(MentionWrapper, { id: "".concat(guid).concat(MENTION_WRAPPER_ID_POSTFIX) }),
124
133
  showMention && renderMentions(),
125
- React.createElement(MarkdownEditor, __assign({}, textareaProps, { maxRows: fullscreen ? undefined : textareaProps.maxRows, width: width, textareaRef: textareaRef, onChange: listenChange, onSelect: listenSelection, onClick: listenClick }))));
134
+ React.createElement(MarkdownEditor, __assign({}, textareaProps, { maxRows: fullscreen ? undefined : textareaProps.maxRows, width: width, textareaRef: textareaRef, onChange: listenChange, onSelect: listenSelect, onClick: listenClick }))));
126
135
  }
127
136
  function renderPreview() {
128
137
  var _a;
@@ -131,9 +140,7 @@ export var Markdown = function (props) {
131
140
  return (React.createElement(MarkdownPreview, __assign({}, horizontalPaddings, { viewMode: viewMode, width: width }), (markdownViewer === null || markdownViewer === void 0 ? void 0 : markdownViewer(props.value)) || (React.createElement(MarkdownViewer, { source: (_a = props.value) !== null && _a !== void 0 ? _a : '', downloadFileApi: api === null || api === void 0 ? void 0 : api.fileDownloadApi, fileApiUrl: fileApiUrl, profileUrl: profileUrl }))));
132
141
  }
133
142
  function renderMentions() {
134
- var _a;
135
- if (textareaRef.current && mention && (api === null || api === void 0 ? void 0 : api.getUsersApi)) {
136
- var textareaNode = (_a = textareaRef.current) === null || _a === void 0 ? void 0 : _a.node;
143
+ if (textareaNode && mention && (api === null || api === void 0 ? void 0 : api.getUsersApi)) {
137
144
  var position = getCursorCoordinates(textareaNode, guid);
138
145
  return (React.createElement(MarkdownMention, { value: getMentionValue(mention), getUsersApi: api.getUsersApi, y: position.y, x: position.x, onSelectUser: handleSelectUser }));
139
146
  }
@@ -143,18 +150,13 @@ export var Markdown = function (props) {
143
150
  onChangeViewMode === null || onChangeViewMode === void 0 ? void 0 : onChangeViewMode(mode);
144
151
  }
145
152
  function handleSelectUser(login, name) {
146
- if (textareaRef.current && mention) {
147
- var htmlTextArea = textareaRef.current;
148
- htmlTextArea.setSelectionRange(mention.positions[0] ? mention.positions[0] - 1 : 0, mention.positions[1]);
153
+ if (textareaNode && mention) {
154
+ textareaNode.setSelectionRange(mention.positions[0] ? mention.positions[0] - 1 : 0, mention.positions[1]);
149
155
  document.execCommand('insertText', false, "[".concat(name, "](@").concat(login, ")"));
150
156
  resetMention();
151
157
  }
152
158
  }
153
- function listenSelection(event) {
154
- var _a = event.currentTarget, textSelectionStart = _a.selectionStart, textSelectionEnd = _a.selectionEnd;
155
- console.log('textSelectionStart', textSelectionStart);
156
- setSelectionStart(textSelectionStart);
157
- setSelectionEnd(textSelectionEnd);
159
+ function listenSelect(event) {
158
160
  onSelect && onSelect(event);
159
161
  checkMention(event);
160
162
  }
@@ -174,6 +176,7 @@ export var Markdown = function (props) {
174
176
  resetMention();
175
177
  setSelectionStart(undefined);
176
178
  setSelectionEnd(undefined);
179
+ textareaNode === null || textareaNode === void 0 ? void 0 : textareaNode.setSelectionRange(0, 0);
177
180
  }
178
181
  function resetMention() {
179
182
  setMention(undefined);
@@ -182,4 +185,8 @@ export var Markdown = function (props) {
182
185
  setViewMode(function (prevState) { return (prevState !== ViewMode.Split && isSplitViewAvailable ? ViewMode.Split : ViewMode.Edit); });
183
186
  setFullScreen(!fullscreen);
184
187
  }
188
+ function getTextareaNode() {
189
+ var _a;
190
+ return (_a = textareaRef === null || textareaRef === void 0 ? void 0 : textareaRef.current) === null || _a === void 0 ? void 0 : _a.node;
191
+ }
185
192
  };
@@ -56,7 +56,7 @@ export var ActionsLeftWrapper = styled(ActionsRightWrapper)(templateObject_17 ||
56
56
  export var MarkdownButtonWrapper = styled(Button)(templateObject_18 || (templateObject_18 = __makeTemplateObject(["\n button {\n padding: 4px;\n border: none;\n box-sizing: border-box;\n }\n"], ["\n button {\n padding: 4px;\n border: none;\n box-sizing: border-box;\n }\n"])));
57
57
  export var MarkdownButtonIcon = styled.div(templateObject_19 || (templateObject_19 = __makeTemplateObject(["\n height: 24px;\n display: flex;\n width: 100%;\n align-items: center;\n justify-content: center;\n"], ["\n height: 24px;\n display: flex;\n width: 100%;\n align-items: center;\n justify-content: center;\n"])));
58
58
  export var MarkdownSymbolWrapper = styled.span(templateObject_20 || (templateObject_20 = __makeTemplateObject(["\n color: ", ";\n font-weight: 700;\n"], ["\n color: ", ";\n font-weight: 700;\n"])), function (p) { return p.theme.colors.brand; });
59
- export var MarkdownMenuItem = styled(MenuItem)(templateObject_21 || (templateObject_21 = __makeTemplateObject(["\n padding-left: 8px;\n padding-right: 8px;\n color: ", ";\n"], ["\n padding-left: 8px;\n padding-right: 8px;\n color: ", ";\n"])), function (p) { return p.theme.colors.grayDefault; });
59
+ export var MarkdownMenuItem = styled(MenuItem)(templateObject_21 || (templateObject_21 = __makeTemplateObject(["\n padding-left: 8px;\n padding-right: 8px;\n color: ", ";\n"], ["\n padding-left: 8px;\n padding-right: 8px;\n color: ", ";\n"])), function (p) { return p.theme.colors.text; });
60
60
  export var MarkdownEditorBlock = styled.div(templateObject_22 || (templateObject_22 = __makeTemplateObject(["\n position: relative;\n"], ["\n position: relative;\n"])));
61
61
  export var getMarkdownMentionStyle = function (x, y) { return ({
62
62
  position: 'absolute',
@@ -1,13 +1,10 @@
1
1
  import { Textarea } from '@skbkontur/react-ui';
2
2
  import { FC, RefObject } from 'react';
3
- import { AIMethod, Nullable } from '../../types';
3
+ import { AIApi } from '../../types';
4
4
  interface Props {
5
- api: (query: string, type: string) => Promise<string>;
6
- availableMethods: AIMethod[];
5
+ api: AIApi;
7
6
  textareaRef: RefObject<Textarea>;
8
7
  isPreviewMode?: boolean;
9
- selectionEnd?: Nullable<number>;
10
- selectionStart?: Nullable<number>;
11
8
  }
12
9
  export declare const AIActionsDropdown: FC<Props>;
13
10
  export {};
@@ -34,41 +34,55 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
34
34
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
35
  }
36
36
  };
37
- import { Button, Spinner, Toast, Tooltip } from '@skbkontur/react-ui';
37
+ import { Button, Hint, Spinner, Toast, Tooltip } from '@skbkontur/react-ui';
38
38
  import React, { useEffect, useRef, useState } from 'react';
39
- import { TooltipWrapper } from './AIActionsDropdown.styled';
39
+ import { DropdownCaptionWrapper, TooltipButtonsWrapper, TooltipWrapper } from './AIActionsDropdown.styled';
40
+ import { COPY_BUTTON_TEXT, ERRORS_NOT_FOUND_TEXT } from './constants';
41
+ import { Copy } from '../../../MarkdownIcons/Copy';
42
+ import { NatureFxSparkleA2 } from '../../../MarkdownIcons/NatureFxSparkleA2';
40
43
  import { MarkdownMenuItem } from '../../Markdown.styled';
41
44
  import { Guid } from '../../utils/guid';
42
45
  import { RequestStatus } from '../../utils/requestStatus';
43
46
  import { MarkdownDropdown } from '../MarkdownDropdown/MarkdownDropdown';
44
47
  export var AIActionsDropdown = function (_a) {
45
- var selectionStart = _a.selectionStart, selectionEnd = _a.selectionEnd, textareaRef = _a.textareaRef, isPreviewMode = _a.isPreviewMode, availableMethods = _a.availableMethods, api = _a.api;
46
- var _b = useState(), processedText = _b[0], setProcessedText = _b[1];
47
- var _c = useState(RequestStatus.Default), requestStatus = _c[0], setRequestStatus = _c[1];
48
+ var _b;
49
+ var textareaRef = _a.textareaRef, isPreviewMode = _a.isPreviewMode, api = _a.api;
50
+ var _c = useState(), processedText = _c[0], setProcessedText = _c[1];
51
+ var _d = useState(RequestStatus.Default), requestStatus = _d[0], setRequestStatus = _d[1];
48
52
  var tooltipRef = useRef(null);
49
53
  var taskIdRef = useRef(new Guid());
54
+ var availableMethods = api.availableMethods, onSendMessage = api.onSendMessage;
55
+ var htmlTextArea = (_b = textareaRef.current) === null || _b === void 0 ? void 0 : _b.node;
56
+ var selectionStart = htmlTextArea === null || htmlTextArea === void 0 ? void 0 : htmlTextArea.selectionStart;
57
+ var selectionEnd = htmlTextArea === null || htmlTextArea === void 0 ? void 0 : htmlTextArea.selectionEnd;
50
58
  useEffect(function () {
51
59
  handleCloseTooltip();
52
- }, [selectionStart, selectionEnd, api]);
60
+ }, [selectionStart, selectionEnd]);
53
61
  if (!(textareaRef === null || textareaRef === void 0 ? void 0 : textareaRef.current))
54
62
  return null;
55
- var htmlTextArea = textareaRef.current.node;
56
- var content = (React.createElement(MarkdownDropdown, { hintText: "\u0418\u0418-\u043F\u043E\u043C\u043E\u0449\u043D\u0438\u043A", caption: "AI", menuWidth: 180, isPreviewMode: isPreviewMode, onOpen: handleCloseTooltip }, availableMethods.map(function (_a) {
57
- var method = _a.method, caption = _a.caption;
58
- return (React.createElement(MarkdownMenuItem, { key: method, onClick: function () { return handleProcessText(method); } }, caption));
59
- })));
60
- return (React.createElement(Tooltip, { ref: tooltipRef, trigger: "manual", render: renderTooltipContent, onClose: handleCloseTooltip }, content));
63
+ var value = htmlTextArea.value.substring(Number(selectionStart), selectionEnd !== null && selectionEnd !== void 0 ? selectionEnd : undefined);
64
+ var isEmptySelected = selectionEnd === selectionStart;
65
+ return (React.createElement(Tooltip, { ref: tooltipRef, pos: "top right", allowedPositions: ['top right', 'right middle', 'bottom right'], trigger: "manual", render: renderTooltipContent, onClose: handleCloseTooltip },
66
+ React.createElement(MarkdownDropdown, { hintText: isEmptySelected ? 'Выдели текст' : 'ИИ-помощник', caption: React.createElement(DropdownCaptionWrapper, null,
67
+ React.createElement(NatureFxSparkleA2, null),
68
+ " \u0418\u0418"), menuWidth: 180, disabled: isPreviewMode || isEmptySelected, onOpen: handleCloseTooltip }, availableMethods.map(function (_a) {
69
+ var method = _a.method, caption = _a.caption;
70
+ return (React.createElement(MarkdownMenuItem, { key: method, onClick: function () { return handleProcessText(method); } }, caption));
71
+ }))));
61
72
  function renderTooltipContent() {
62
73
  if (requestStatus === RequestStatus.isFetching)
63
74
  return React.createElement(Spinner, { caption: "\u041E\u0431\u0440\u0430\u0431\u0430\u0442\u044B\u0432\u0430\u0435\u043C", type: "mini" });
64
75
  return (React.createElement(TooltipWrapper, null,
65
76
  React.createElement("div", null, processedText),
66
- React.createElement(Button, { onClick: handleSetText }, "\u0417\u0430\u043C\u0435\u043D\u0438\u0442\u044C \u0442\u0435\u043A\u0441\u0442")));
77
+ processedText !== ERRORS_NOT_FOUND_TEXT && (React.createElement(TooltipButtonsWrapper, null,
78
+ React.createElement(Button, { onClick: handleSetText }, "\u0417\u0430\u043C\u0435\u043D\u0438\u0442\u044C \u0442\u0435\u043A\u0441\u0442"),
79
+ React.createElement(Hint, { text: COPY_BUTTON_TEXT },
80
+ React.createElement(Button, { "aria-label": COPY_BUTTON_TEXT, icon: React.createElement(Copy, null), onClick: handleCopyText }))))));
67
81
  }
68
82
  function handleProcessText(method) {
69
83
  var _a;
70
84
  return __awaiter(this, void 0, void 0, function () {
71
- var taskId, value, response, e_1;
85
+ var taskId, response, e_1;
72
86
  return __generator(this, function (_b) {
73
87
  switch (_b.label) {
74
88
  case 0:
@@ -76,17 +90,17 @@ export var AIActionsDropdown = function (_a) {
76
90
  (_a = tooltipRef === null || tooltipRef === void 0 ? void 0 : tooltipRef.current) === null || _a === void 0 ? void 0 : _a.show();
77
91
  taskId = taskIdRef.current.generate();
78
92
  setRequestStatus(RequestStatus.isFetching);
79
- value = htmlTextArea.value.substring(Number(selectionStart), selectionEnd !== null && selectionEnd !== void 0 ? selectionEnd : undefined);
80
- return [4 /*yield*/, api(value, method)];
93
+ return [4 /*yield*/, onSendMessage(value, method)];
81
94
  case 1:
82
95
  response = _b.sent();
83
96
  if (response && taskId === taskIdRef.current.generated) {
84
97
  setRequestStatus(RequestStatus.isLoaded);
85
- setProcessedText(response);
98
+ setProcessedText(value === response ? ERRORS_NOT_FOUND_TEXT : response);
86
99
  }
87
100
  return [3 /*break*/, 3];
88
101
  case 2:
89
102
  e_1 = _b.sent();
103
+ handleCloseTooltip();
90
104
  Toast.push('Ошибка обработки текста');
91
105
  return [3 /*break*/, 3];
92
106
  case 3: return [2 /*return*/];
@@ -94,10 +108,27 @@ export var AIActionsDropdown = function (_a) {
94
108
  });
95
109
  });
96
110
  }
111
+ function handleCopyText() {
112
+ return __awaiter(this, void 0, void 0, function () {
113
+ return __generator(this, function (_a) {
114
+ switch (_a.label) {
115
+ case 0: return [4 /*yield*/, navigator.clipboard.writeText(processedText || '')];
116
+ case 1:
117
+ _a.sent();
118
+ handleCloseTooltip();
119
+ return [2 /*return*/];
120
+ }
121
+ });
122
+ });
123
+ }
97
124
  function handleSetText() {
98
125
  if (!(textareaRef === null || textareaRef === void 0 ? void 0 : textareaRef.current))
99
126
  return null;
100
127
  textareaRef.current.focus();
128
+ var valueLength = value.length;
129
+ var spaceInStartCount = valueLength - value.trimStart().length;
130
+ var spaceInEndCount = valueLength - value.trimEnd().length;
131
+ htmlTextArea.setSelectionRange(selectionStart + spaceInStartCount, selectionEnd - spaceInEndCount);
101
132
  document.execCommand('insertText', false, processedText);
102
133
  handleCloseTooltip();
103
134
  }
@@ -1 +1,3 @@
1
1
  export declare const TooltipWrapper: import("styled-components").StyledComponent<"div", import("../../../..").MarkdownTheme, {}, never>;
2
+ export declare const TooltipButtonsWrapper: import("styled-components").StyledComponent<"div", import("../../../..").MarkdownTheme, {}, never>;
3
+ export declare const DropdownCaptionWrapper: import("styled-components").StyledComponent<"div", import("../../../..").MarkdownTheme, {}, never>;
@@ -4,4 +4,6 @@ var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cook
4
4
  };
5
5
  import styled from '../../../styles/styled-components';
6
6
  export var TooltipWrapper = styled.div(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n display: flex;\n flex-direction: column;\n gap: 16px;\n max-width: 300px;\n"], ["\n display: flex;\n flex-direction: column;\n gap: 16px;\n max-width: 300px;\n"])));
7
- var templateObject_1;
7
+ export var TooltipButtonsWrapper = styled.div(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n display: flex;\n align-items: center;\n gap: 8px;\n"], ["\n display: flex;\n align-items: center;\n gap: 8px;\n"])));
8
+ export var DropdownCaptionWrapper = styled.div(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n display: flex;\n align-items: center;\n gap: 4px;\n"], ["\n display: flex;\n align-items: center;\n gap: 4px;\n"])));
9
+ var templateObject_1, templateObject_2, templateObject_3;
@@ -0,0 +1,2 @@
1
+ export declare const ERRORS_NOT_FOUND_TEXT = "\u041E\u0448\u0438\u0431\u043E\u043A \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E";
2
+ export declare const COPY_BUTTON_TEXT = "\u0421\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C";
@@ -0,0 +1,2 @@
1
+ export var ERRORS_NOT_FOUND_TEXT = 'Ошибок не найдено';
2
+ export var COPY_BUTTON_TEXT = 'Скопировать';
@@ -1,7 +1,7 @@
1
1
  import { Textarea } from '@skbkontur/react-ui';
2
2
  import { FC, RefObject } from 'react';
3
3
  import { EmojiData } from '../Emoji/Emoji.logic';
4
- import { AIMethod, HideActionsOptions, HorizontalPaddings, Nullable, ViewMode } from '../types';
4
+ import { AIApi, HideActionsOptions, HorizontalPaddings, Nullable, ViewMode } from '../types';
5
5
  interface Props {
6
6
  horizontalPaddings: HorizontalPaddings;
7
7
  onChangeViewMode: (viewMode: ViewMode) => void;
@@ -12,12 +12,12 @@ interface Props {
12
12
  showShortKeys: boolean;
13
13
  textAreaRef: RefObject<Textarea>;
14
14
  viewMode: ViewMode;
15
- AIApi?: (query: string, method: string) => Promise<string>;
16
- availableAIMethods?: AIMethod[];
15
+ AIApi?: AIApi;
17
16
  disableFullscreen?: boolean;
18
17
  fullscreen?: boolean;
19
18
  hasFilesApi?: boolean;
20
19
  hideOptions?: HideActionsOptions;
20
+ isFocused?: boolean;
21
21
  isSplitViewAvailable?: boolean;
22
22
  loadingFile?: boolean;
23
23
  selectionEnd?: Nullable<number>;
@@ -28,12 +28,12 @@ import { setMarkdown } from '../MarkdownHelpers/markdownHelpers';
28
28
  import { markdownHelpHeaders, markdownHelpLists, markdownHelpOther, markdownHelpText } from '../MarkdownHelpItems';
29
29
  import { ViewMode } from '../types';
30
30
  export var MarkdownActions = function (_a) {
31
- var textAreaRef = _a.textAreaRef, selectionStart = _a.selectionStart, selectionEnd = _a.selectionEnd, loadingFile = _a.loadingFile, onOpenFileDialog = _a.onOpenFileDialog, onClickFullscreen = _a.onClickFullscreen, fullscreen = _a.fullscreen, viewMode = _a.viewMode, onChangeViewMode = _a.onChangeViewMode, horizontalPaddings = _a.horizontalPaddings, hasFilesApi = _a.hasFilesApi, width = _a.width, showActionHints = _a.showActionHints, showShortKeys = _a.showShortKeys, hideOptions = _a.hideOptions, onSelectEmoji = _a.onSelectEmoji, isSplitViewAvailable = _a.isSplitViewAvailable, disableFullscreen = _a.disableFullscreen, availableAIMethods = _a.availableAIMethods, AIApi = _a.AIApi;
31
+ var textAreaRef = _a.textAreaRef, selectionStart = _a.selectionStart, selectionEnd = _a.selectionEnd, loadingFile = _a.loadingFile, onOpenFileDialog = _a.onOpenFileDialog, onClickFullscreen = _a.onClickFullscreen, fullscreen = _a.fullscreen, viewMode = _a.viewMode, onChangeViewMode = _a.onChangeViewMode, horizontalPaddings = _a.horizontalPaddings, hasFilesApi = _a.hasFilesApi, width = _a.width, showActionHints = _a.showActionHints, showShortKeys = _a.showShortKeys, hideOptions = _a.hideOptions, onSelectEmoji = _a.onSelectEmoji, isSplitViewAvailable = _a.isSplitViewAvailable, disableFullscreen = _a.disableFullscreen, AIApi = _a.AIApi;
32
32
  var isPreviewMode = viewMode === ViewMode.Preview;
33
33
  return (React.createElement(MarkdownActionsWrapper, __assign({}, horizontalPaddings, { width: width, fullscreen: fullscreen }),
34
34
  React.createElement(ButtonsWrapper, { fullscreen: fullscreen },
35
35
  React.createElement(ActionsLeftWrapper, null,
36
- !(hideOptions === null || hideOptions === void 0 ? void 0 : hideOptions.heading) && (React.createElement(MarkdownDropdown, { caption: "H", hintText: "\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A", isPreviewMode: isPreviewMode }, markdownHelpHeaders.map(function (helper, idx) { return (React.createElement(MarkdownMenuItem, { key: idx, onClick: function (event) { return handleMarkdownItemClick(event, helper.format); } },
36
+ !(hideOptions === null || hideOptions === void 0 ? void 0 : hideOptions.heading) && (React.createElement(MarkdownDropdown, { caption: "H", hintText: "\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A", disabled: isPreviewMode }, markdownHelpHeaders.map(function (helper, idx) { return (React.createElement(MarkdownMenuItem, { key: idx, onClick: function (event) { return handleMarkdownItemClick(event, helper.format); } },
37
37
  React.createElement(MarkdownCombination, { showShortKey: showShortKeys, format: helper.format, text: helper.node }))); }))),
38
38
  markdownHelpText.map(function (helper, idx) {
39
39
  if (isHiddenOptions(helper.format))
@@ -52,9 +52,9 @@ export var MarkdownActions = function (_a) {
52
52
  }),
53
53
  hasFilesApi && !(hideOptions === null || hideOptions === void 0 ? void 0 : hideOptions.file) && (React.createElement(MarkdownFormatButton, { hintText: "\u041F\u0440\u0438\u043A\u0440\u0435\u043F\u0438\u0442\u044C \u0444\u0430\u0439\u043B", showActionHint: showActionHints, showShortKey: showShortKeys, disabled: isPreviewMode, isLoading: loadingFile, icon: React.createElement(AttachPaperclip, null), text: "\u041F\u0440\u0438\u043A\u0440\u0435\u043F\u0438\u0442\u044C \u0444\u0430\u0439\u043B", onClick: onOpenFileDialog })),
54
54
  !(hideOptions === null || hideOptions === void 0 ? void 0 : hideOptions.emoji) && (React.createElement(EmojiDropdown, { showShortKey: showShortKeys, isPreviewMode: isPreviewMode, onSelect: onSelectEmoji })),
55
- !(hideOptions === null || hideOptions === void 0 ? void 0 : hideOptions.help) && (React.createElement(MarkdownFormatButton, { hintText: "\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\u0446\u0438\u044F Markdown", icon: React.createElement(DocIcon, null), text: "\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\u0446\u0438\u044F Markdown", href: COMMONMARK_HELP_URL })),
56
- !(hideOptions === null || hideOptions === void 0 ? void 0 : hideOptions.AI) && !!(availableAIMethods === null || availableAIMethods === void 0 ? void 0 : availableAIMethods.length) && !!AIApi && (React.createElement(AIActionsDropdown, { textareaRef: textAreaRef, isPreviewMode: isPreviewMode, selectionStart: selectionStart, selectionEnd: selectionEnd, availableMethods: availableAIMethods, api: AIApi }))),
55
+ !(hideOptions === null || hideOptions === void 0 ? void 0 : hideOptions.AI) && !!AIApi && (React.createElement(AIActionsDropdown, { textareaRef: textAreaRef, isPreviewMode: isPreviewMode, api: AIApi }))),
57
56
  React.createElement(ActionsRightWrapper, null,
57
+ !(hideOptions === null || hideOptions === void 0 ? void 0 : hideOptions.help) && (React.createElement(MarkdownFormatButton, { hintText: "\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\u0446\u0438\u044F Markdown", icon: React.createElement(DocIcon, null), text: "\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\u0446\u0438\u044F Markdown", href: COMMONMARK_HELP_URL })),
58
58
  !(hideOptions === null || hideOptions === void 0 ? void 0 : hideOptions.viewMode) && renderViewModeButton(),
59
59
  !(hideOptions === null || hideOptions === void 0 ? void 0 : hideOptions.screenMode) && !disableFullscreen && (React.createElement(MarkdownFormatButton, { hintText: fullscreen ? 'Свернуть' : 'Развернуть', icon: fullscreen ? React.createElement(Collapse, null) : React.createElement(Expand, null), text: fullscreen ? 'Свернуть' : ' Развернуть', onClick: onClickFullscreen }))))));
60
60
  function renderViewModeButton() {
@@ -1,8 +1,9 @@
1
- import { FC, PropsWithChildren } from 'react';
1
+ import { FC, PropsWithChildren, ReactElement, ReactNode } from 'react';
2
2
  interface Props {
3
- caption: string;
3
+ caption: ReactNode;
4
+ disabled?: boolean;
4
5
  hintText?: string;
5
- isPreviewMode?: boolean;
6
+ icon?: ReactElement;
6
7
  menuWidth?: number;
7
8
  onOpen?: () => void;
8
9
  }
@@ -2,11 +2,11 @@ import { Dropdown, Hint } from '@skbkontur/react-ui';
2
2
  import React, { useState } from 'react';
3
3
  import { Wrapper } from './MarkdownDropdown.styled';
4
4
  export var MarkdownDropdown = function (_a) {
5
- var isPreviewMode = _a.isPreviewMode, children = _a.children, caption = _a.caption, onOpen = _a.onOpen, menuWidth = _a.menuWidth, hintText = _a.hintText;
5
+ var icon = _a.icon, disabled = _a.disabled, children = _a.children, caption = _a.caption, onOpen = _a.onOpen, menuWidth = _a.menuWidth, hintText = _a.hintText;
6
6
  var _b = useState(false), isOpened = _b[0], setIsOpened = _b[1];
7
7
  return (React.createElement(Wrapper, { onMouseDown: function (e) { return e.preventDefault(); } },
8
8
  React.createElement(Hint, { text: hintText, pos: "top left", manual: isOpened, opened: !isOpened },
9
- React.createElement(Dropdown, { disablePortal: true, disabled: isPreviewMode, menuWidth: menuWidth !== null && menuWidth !== void 0 ? menuWidth : 300, caption: caption, onOpen: handleOpen, onClose: function () { return setIsOpened(false); } }, children))));
9
+ React.createElement(Dropdown, { disablePortal: true, disabled: disabled, menuWidth: menuWidth !== null && menuWidth !== void 0 ? menuWidth : 300, caption: caption, icon: icon, onOpen: handleOpen, onClose: function () { return setIsOpened(false); } }, children))));
10
10
  function handleOpen() {
11
11
  onOpen === null || onOpen === void 0 ? void 0 : onOpen();
12
12
  setIsOpened(true);
@@ -25,9 +25,19 @@ export interface User {
25
25
  teams: RefItem[];
26
26
  sid?: string;
27
27
  }
28
- export interface MarkdownApi {
28
+ export interface AIMethod {
29
+ caption: string;
30
+ method: string;
31
+ }
32
+ export interface AIApi {
33
+ /** Доступные методы ИИ апи */
34
+ availableMethods: AIMethod[];
29
35
  /** Метод для обработки текста с помощью ИИ */
30
- AIApi?: (query: string, method: string) => Promise<string>;
36
+ onSendMessage: (query: string, method: string) => Promise<Nullable<string>>;
37
+ }
38
+ export interface MarkdownApi {
39
+ /** Апи для взаимодействия с ИИ */
40
+ AIApi?: AIApi;
31
41
  /** Метод для загрузки файла */
32
42
  fileDownloadApi?: (id: string) => Promise<File>;
33
43
  /** Метод для скачивания файла */
@@ -42,7 +52,3 @@ export interface TestCase<V, E> {
42
52
  }
43
53
  export type ReactUIThemeType = Partial<typeof THEME_2022>;
44
54
  export type HideActionsOptions = Partial<Record<MarkdownFormat | 'heading' | 'emoji' | 'viewMode' | 'screenMode' | 'help' | 'allActions' | 'AI', boolean>>;
45
- export interface AIMethod {
46
- caption: string;
47
- method: string;
48
- }
@@ -0,0 +1,2 @@
1
+ import { FC } from 'react';
2
+ export declare const Copy: FC;
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ export var Copy = function () {
3
+ return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 20 20", fill: "none" },
4
+ React.createElement("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M7 2C5.34315 2 4 3.34315 4 5V15C4 16.6569 5.34315 18 7 18H13C14.6569 18 16 16.6569 16 15V5C16 3.34315 14.6569 2 13 2H7ZM5 5C5 3.89543 5.89543 3 7 3H13C14.1046 3 15 3.89543 15 5V15C15 16.1046 14.1046 17 13 17H7C5.89543 17 5 16.1046 5 15V5Z", fill: "currentColor" }),
5
+ React.createElement("path", { d: "M18 8.5C18 8.22386 17.7761 8 17.5 8C17.2239 8 17 8.22386 17 8.5V15.5C17 17.433 15.433 19 13.5 19H8.5C8.22386 19 8 19.2239 8 19.5C8 19.7761 8.22386 20 8.5 20H13.5C15.9853 20 18 17.9853 18 15.5V8.5Z", fill: "currentColor" })));
6
+ };
@@ -0,0 +1,2 @@
1
+ import { FC } from 'react';
2
+ export declare const NatureFxSparkleA2: FC;
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ export var NatureFxSparkleA2 = function () {
3
+ return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 20 20", fill: "none" },
4
+ React.createElement("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M15.0413 1.49763C14.9148 0.934973 14.0776 0.935061 13.9512 1.49773C13.8878 1.77985 13.7684 2.24714 13.5864 2.72017C13.3999 3.20461 13.1678 3.64088 12.9029 3.90557C12.6384 4.16985 12.2027 4.40143 11.719 4.5875C11.2466 4.7692 10.7799 4.88837 10.4978 4.9517C9.93495 5.07806 9.93504 5.91564 10.4979 6.0419C10.7802 6.1052 11.2472 6.22439 11.7199 6.40617C12.204 6.59234 12.6399 6.82409 12.9044 7.08863C13.1689 7.35316 13.4007 7.78906 13.5869 8.27315C13.7686 8.74585 13.8878 9.21288 13.9511 9.49509C14.0774 10.058 14.915 10.0581 15.0413 9.4952C15.1047 9.21313 15.2238 8.74645 15.4055 8.27407C15.5916 7.79031 15.8232 7.35465 16.0875 7.09015C16.3521 6.82526 16.7884 6.59315 17.2729 6.40668C17.7459 6.2246 18.2132 6.10521 18.4953 6.04183C19.058 5.91544 19.0581 5.07826 18.4954 4.95176C18.2134 4.88837 17.7465 4.76899 17.2738 4.587C16.7897 4.40062 16.3536 4.16869 16.089 3.90404C15.8243 3.6394 15.5924 3.20335 15.406 2.71926C15.224 2.24654 15.1047 1.77959 15.0413 1.49763ZM14.4964 3.139C14.9555 4.30255 15.6905 5.03751 16.854 5.49666C15.6907 5.95548 14.9553 6.68969 14.4964 7.85299C14.0378 6.68993 13.3031 5.95528 12.14 5.49666C13.3033 5.03771 14.0376 4.30231 14.4964 3.139Z", fill: "currentColor" }),
5
+ React.createElement("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M7.55535 5.97566C7.42933 5.39847 6.56967 5.39855 6.44376 5.97577C6.3559 6.37855 6.17724 7.10496 5.89522 7.85362C5.60854 8.61465 5.23608 9.34063 4.78623 9.79012C4.33703 10.239 3.61201 10.6106 2.85198 10.8967C2.10429 11.1781 1.37878 11.3565 0.976004 11.4443C0.398567 11.5701 0.398646 12.4302 0.976106 12.556C1.37908 12.6438 2.10513 12.8221 2.85332 13.1037C3.61387 13.3899 4.33931 13.7618 4.78859 14.2111C5.23788 14.6604 5.60979 15.3858 5.89601 16.1464C6.17759 16.8946 6.35592 17.6206 6.44369 18.0236C6.56945 18.601 7.42955 18.6011 7.55542 18.0237C7.64322 17.6209 7.82156 16.8954 8.10299 16.1477C8.38907 15.3877 8.76071 14.6627 9.20956 14.2134C9.65905 13.7636 10.385 13.3911 11.1461 13.1045C11.8947 12.8224 12.6211 12.6438 13.0239 12.5559C13.6011 12.43 13.6012 11.5703 13.024 11.4443C12.6214 11.3564 11.8956 11.1778 11.1474 10.8959C10.3869 10.6094 9.66133 10.2372 9.21192 9.78776C8.76251 9.33836 8.39031 8.61279 8.10378 7.85228C7.8219 7.10412 7.64324 6.37824 7.55535 5.97566ZM6.99971 7.72905C7.32853 8.71941 7.75702 9.74708 8.50481 10.4949C9.25261 11.2427 10.2803 11.6712 11.2706 12C10.2793 12.329 9.25042 12.7578 8.50217 13.5066C7.75568 14.2537 7.32793 15.2799 6.99971 16.269C6.67134 15.2789 6.24323 14.2515 5.4957 13.504C4.74817 12.7564 3.72074 12.3283 2.73064 12C3.71974 11.6718 4.74597 11.244 5.49306 10.4975C6.2419 9.74927 6.67074 8.72041 6.99971 7.72905Z", fill: "currentColor" })));
6
+ };