@gravity-ui/markdown-editor 13.22.0 → 13.24.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.
- package/build/cjs/bundle/MarkdownEditorView.css +1 -0
- package/build/cjs/bundle/MarkdownEditorView.d.ts +5 -2
- package/build/cjs/bundle/MarkdownEditorView.js +30 -12
- package/build/cjs/bundle/config/index.d.ts +1 -0
- package/build/cjs/bundle/config/index.js +1 -0
- package/build/cjs/extensions/markdown/Lists/ListsSpecs/const.d.ts +11 -2
- package/build/cjs/extensions/markdown/Lists/ListsSpecs/const.js +12 -3
- package/build/cjs/extensions/markdown/Lists/ListsSpecs/parser.js +2 -0
- package/build/cjs/extensions/markdown/Lists/ListsSpecs/schema.js +14 -3
- package/build/cjs/extensions/markdown/Lists/ListsSpecs/serializer.js +16 -3
- package/build/cjs/extensions/yfm/Math/commands.d.ts +6 -2
- package/build/cjs/extensions/yfm/Math/commands.js +33 -7
- package/build/cjs/extensions/yfm/Math/index.js +1 -1
- package/build/cjs/extensions/yfm/Math/view-and-edit.js +4 -4
- package/build/cjs/extensions/yfm/YfmCut/YfmCutSpecs/schema.js +6 -6
- package/build/cjs/extensions/yfm/YfmCut/actions/toYfmCut.js +1 -1
- package/build/cjs/extensions/yfm/YfmCut/index.css +12 -0
- package/build/cjs/extensions/yfm/YfmCut/nodeviews/yfm-cut-title.js +2 -1
- package/build/cjs/extensions/yfm/YfmCut/plugins/auto-open.js +3 -1
- package/build/cjs/i18n/menubar/index.d.ts +1 -1
- package/build/cjs/version.js +1 -1
- package/build/esm/bundle/MarkdownEditorView.css +1 -0
- package/build/esm/bundle/MarkdownEditorView.d.ts +5 -2
- package/build/esm/bundle/MarkdownEditorView.js +26 -8
- package/build/esm/bundle/config/index.d.ts +1 -0
- package/build/esm/bundle/config/index.js +1 -0
- package/build/esm/extensions/markdown/Lists/ListsSpecs/const.d.ts +11 -2
- package/build/esm/extensions/markdown/Lists/ListsSpecs/const.js +11 -2
- package/build/esm/extensions/markdown/Lists/ListsSpecs/parser.js +2 -0
- package/build/esm/extensions/markdown/Lists/ListsSpecs/schema.js +15 -4
- package/build/esm/extensions/markdown/Lists/ListsSpecs/serializer.js +17 -4
- package/build/esm/extensions/yfm/Math/commands.d.ts +6 -2
- package/build/esm/extensions/yfm/Math/commands.js +30 -5
- package/build/esm/extensions/yfm/Math/index.js +2 -2
- package/build/esm/extensions/yfm/Math/view-and-edit.js +6 -5
- package/build/esm/extensions/yfm/YfmCut/YfmCutSpecs/schema.js +6 -6
- package/build/esm/extensions/yfm/YfmCut/actions/toYfmCut.js +1 -1
- package/build/esm/extensions/yfm/YfmCut/index.css +12 -0
- package/build/esm/extensions/yfm/YfmCut/nodeviews/yfm-cut-title.js +2 -1
- package/build/esm/extensions/yfm/YfmCut/plugins/auto-open.js +3 -1
- package/build/esm/i18n/menubar/index.d.ts +1 -1
- package/build/esm/version.js +1 -1
- package/build/styles.css +13 -0
- package/package.json +3 -3
|
@@ -2,8 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import type { ToasterPublicMethods } from '@gravity-ui/uikit';
|
|
3
3
|
import { ClassNameProps } from '../classname';
|
|
4
4
|
import type { Editor } from './Editor';
|
|
5
|
-
import { MToolbarData, MToolbarItemData } from './config
|
|
6
|
-
import { WToolbarData, WToolbarItemData } from './config/wysiwyg';
|
|
5
|
+
import { MToolbarData, MToolbarItemData, WToolbarData, WToolbarItemData } from './config';
|
|
7
6
|
export declare const cnEditorComponent: import("@bem-react/classname").ClassNameFormatter;
|
|
8
7
|
export declare type MarkdownEditorViewProps = ClassNameProps & {
|
|
9
8
|
editor?: Editor;
|
|
@@ -16,6 +15,8 @@ export declare type MarkdownEditorViewProps = ClassNameProps & {
|
|
|
16
15
|
settingsVisible?: boolean;
|
|
17
16
|
toaster: ToasterPublicMethods;
|
|
18
17
|
stickyToolbar: boolean;
|
|
18
|
+
enableSubmitInPreview?: boolean;
|
|
19
|
+
hidePreviewAfterSubmit?: boolean;
|
|
19
20
|
};
|
|
20
21
|
export declare const MarkdownEditorView: React.ForwardRefExoticComponent<ClassNameProps & {
|
|
21
22
|
editor?: Editor | undefined;
|
|
@@ -28,4 +29,6 @@ export declare const MarkdownEditorView: React.ForwardRefExoticComponent<ClassNa
|
|
|
28
29
|
settingsVisible?: boolean | undefined;
|
|
29
30
|
toaster: ToasterPublicMethods;
|
|
30
31
|
stickyToolbar: boolean;
|
|
32
|
+
enableSubmitInPreview?: boolean | undefined;
|
|
33
|
+
hidePreviewAfterSubmit?: boolean | undefined;
|
|
31
34
|
} & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -8,16 +8,13 @@ const react_use_1 = require("react-use");
|
|
|
8
8
|
const classname_1 = require("../classname");
|
|
9
9
|
const bundle_1 = require("../i18n/bundle");
|
|
10
10
|
const logger_1 = require("../logger");
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const useSticky_1 = require("../react-utils/useSticky");
|
|
14
|
-
const platform_1 = require("../utils/platform");
|
|
11
|
+
const react_utils_1 = require("../react-utils");
|
|
12
|
+
const utils_1 = require("../utils");
|
|
15
13
|
const HorizontalDrag_1 = require("./HorizontalDrag");
|
|
16
14
|
const MarkupEditorView_1 = require("./MarkupEditorView");
|
|
17
15
|
const SplitModeView_1 = require("./SplitModeView");
|
|
18
16
|
const WysiwygEditorView_1 = require("./WysiwygEditorView");
|
|
19
|
-
const
|
|
20
|
-
const wysiwyg_1 = require("./config/wysiwyg");
|
|
17
|
+
const config_1 = require("./config");
|
|
21
18
|
const context_1 = require("./context");
|
|
22
19
|
const settings_1 = require("./settings");
|
|
23
20
|
const sticky_1 = require("./sticky");
|
|
@@ -31,12 +28,12 @@ exports.MarkdownEditorView = react_1.default.forwardRef((props, ref) => {
|
|
|
31
28
|
(0, react_1.useEffect)(() => {
|
|
32
29
|
setIsMounted(true);
|
|
33
30
|
}, []);
|
|
34
|
-
const [showPreview, , unsetShowPreview, toggleShowPreview] = (0,
|
|
31
|
+
const [showPreview, , unsetShowPreview, toggleShowPreview] = (0, react_utils_1.useBooleanState)(false);
|
|
35
32
|
const context = (0, context_1.useMarkdownEditorContext)();
|
|
36
33
|
const editor = ((_a = props.editor) !== null && _a !== void 0 ? _a : context);
|
|
37
34
|
if (!editor)
|
|
38
35
|
throw new Error('[MarkdownEditorView]: an instance of the editor must be passed through the props or context');
|
|
39
|
-
const { autofocus, className, settingsVisible = true, markupToolbarConfig =
|
|
36
|
+
const { autofocus, className, settingsVisible = true, markupToolbarConfig = config_1.mToolbarConfigByPreset[editor.preset], wysiwygToolbarConfig = config_1.wToolbarConfigByPreset[editor.preset], markupHiddenActionsConfig = config_1.mHiddenDataByPreset[editor.preset], wysiwygHiddenActionsConfig = config_1.wHiddenDataByPreset[editor.preset], toaster, stickyToolbar, enableSubmitInPreview = true, hidePreviewAfterSubmit = false, } = props;
|
|
40
37
|
const rerender = (0, react_use_1.useUpdate)();
|
|
41
38
|
react_1.default.useLayoutEffect(() => {
|
|
42
39
|
editor.on('rerender', rerender);
|
|
@@ -66,6 +63,20 @@ exports.MarkdownEditorView = react_1.default.forwardRef((props, ref) => {
|
|
|
66
63
|
(0, react_use_1.useKey)((e) => canRenderPreview && isPreviewKeyDown(e), () => onShowPreviewChange(!showPreview), { event: 'keydown' }, [showPreview, editorMode, onShowPreviewChange, canRenderPreview]);
|
|
67
64
|
const editorWrapperRef = (0, react_1.useRef)(null);
|
|
68
65
|
const splitModeViewWrapperRef = (0, react_1.useRef)(null);
|
|
66
|
+
(0, react_1.useEffect)(() => {
|
|
67
|
+
if (showPreview) {
|
|
68
|
+
divRef.current.focus();
|
|
69
|
+
}
|
|
70
|
+
}, [divRef, showPreview]);
|
|
71
|
+
(0, react_use_1.useKey)((e) => enableSubmitInPreview &&
|
|
72
|
+
showPreview &&
|
|
73
|
+
isWrapperFocused(divRef) &&
|
|
74
|
+
isSubmitKeyDown(e), () => {
|
|
75
|
+
editor.emit('submit', null);
|
|
76
|
+
if (hidePreviewAfterSubmit) {
|
|
77
|
+
onShowPreviewChange(false);
|
|
78
|
+
}
|
|
79
|
+
}, { event: 'keydown' }, [hidePreviewAfterSubmit, enableSubmitInPreview, showPreview, showPreview]);
|
|
69
80
|
const settings = (0, react_1.useMemo)(() => (react_1.default.createElement(Settings, { mode: editorMode, onModeChange: onModeChange, toolbarVisibility: editor.toolbarVisible && !showPreview, onToolbarVisibilityChange: onToolbarVisibilityChange, onSplitModeChange: onSplitModeChange, splitModeEnabled: editor.splitModeEnabled, splitMode: editor.splitMode, stickyToolbar: stickyToolbar, onShowPreviewChange: onShowPreviewChange, showPreview: showPreview, renderPreviewButton: canRenderPreview })), [
|
|
70
81
|
canRenderPreview,
|
|
71
82
|
stickyToolbar,
|
|
@@ -98,11 +109,11 @@ exports.MarkdownEditorView = react_1.default.forwardRef((props, ref) => {
|
|
|
98
109
|
});
|
|
99
110
|
return null;
|
|
100
111
|
} },
|
|
101
|
-
react_1.default.createElement(
|
|
112
|
+
react_1.default.createElement(react_utils_1.ToasterContext.Provider, { value: toaster },
|
|
102
113
|
react_1.default.createElement("div", { ref: divRef, className: b({
|
|
103
114
|
settings: settingsVisible,
|
|
104
115
|
split: markupSplitMode && editor.splitMode,
|
|
105
|
-
}, [className]) },
|
|
116
|
+
}, [className]), role: "button", tabIndex: 0 },
|
|
106
117
|
react_1.default.createElement("div", { className: b('editor-wrapper'), ref: editorWrapperRef }, showPreview ? (react_1.default.createElement(react_1.default.Fragment, null,
|
|
107
118
|
react_1.default.createElement("div", { className: b('preview-wrapper') }, (_b = editor.renderPreview) === null || _b === void 0 ? void 0 : _b.call(editor, {
|
|
108
119
|
getValue: editor.getValue,
|
|
@@ -120,7 +131,7 @@ exports.MarkdownEditorView.displayName = 'MarkdownEditorView';
|
|
|
120
131
|
const MarkupSearchAnchor = ({ mode }) => (react_1.default.createElement(react_1.default.Fragment, null, mode === 'markup' && react_1.default.createElement("div", { className: "g-md-search-anchor" })));
|
|
121
132
|
function Settings(props) {
|
|
122
133
|
const wrapperRef = (0, react_1.useRef)(null);
|
|
123
|
-
const isSticky = (0,
|
|
134
|
+
const isSticky = (0, react_utils_1.useSticky)(wrapperRef) && props.toolbarVisibility && props.stickyToolbar;
|
|
124
135
|
return (react_1.default.createElement("div", { className: b('settings-wrapper') },
|
|
125
136
|
react_1.default.createElement("div", { ref: wrapperRef, className: sticky_1.stickyCn.settings({
|
|
126
137
|
withToolbar: props.toolbarVisibility,
|
|
@@ -130,6 +141,13 @@ function Settings(props) {
|
|
|
130
141
|
react_1.default.createElement(MarkupSearchAnchor, Object.assign({}, props)))));
|
|
131
142
|
}
|
|
132
143
|
function isPreviewKeyDown(e) {
|
|
133
|
-
const modKey = (0,
|
|
144
|
+
const modKey = (0, utils_1.isMac)() ? e.metaKey : e.ctrlKey;
|
|
134
145
|
return modKey && e.shiftKey && e.code === 'KeyP';
|
|
135
146
|
}
|
|
147
|
+
function isWrapperFocused(divRef) {
|
|
148
|
+
return document.activeElement === divRef.current;
|
|
149
|
+
}
|
|
150
|
+
function isSubmitKeyDown(e) {
|
|
151
|
+
const modKey = (0, utils_1.isMac)() ? e.metaKey : e.ctrlKey;
|
|
152
|
+
return modKey && e.code === 'Enter';
|
|
153
|
+
}
|
|
@@ -5,10 +5,19 @@ export declare enum ListNode {
|
|
|
5
5
|
}
|
|
6
6
|
export declare enum ListsAttr {
|
|
7
7
|
Tight = "tight",
|
|
8
|
-
/**
|
|
8
|
+
/** @deprecated Use `ListsAttr.Markup` instead */
|
|
9
9
|
Bullet = "bullet",
|
|
10
10
|
/** used in ordered list only */
|
|
11
11
|
Order = "order",
|
|
12
|
-
/** used in list item only */
|
|
13
12
|
Markup = "markup"
|
|
14
13
|
}
|
|
14
|
+
export declare const Markup: {
|
|
15
|
+
bullet: {
|
|
16
|
+
values: string[];
|
|
17
|
+
default: string;
|
|
18
|
+
};
|
|
19
|
+
ordered: {
|
|
20
|
+
values: string[];
|
|
21
|
+
default: string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ListsAttr = exports.ListNode = void 0;
|
|
3
|
+
exports.Markup = exports.ListsAttr = exports.ListNode = void 0;
|
|
4
4
|
var ListNode;
|
|
5
5
|
(function (ListNode) {
|
|
6
6
|
ListNode["ListItem"] = "list_item";
|
|
@@ -10,10 +10,19 @@ var ListNode;
|
|
|
10
10
|
var ListsAttr;
|
|
11
11
|
(function (ListsAttr) {
|
|
12
12
|
ListsAttr["Tight"] = "tight";
|
|
13
|
-
/**
|
|
13
|
+
/** @deprecated Use `ListsAttr.Markup` instead */
|
|
14
14
|
ListsAttr["Bullet"] = "bullet";
|
|
15
15
|
/** used in ordered list only */
|
|
16
16
|
ListsAttr["Order"] = "order";
|
|
17
|
-
/** used in list item only */
|
|
18
17
|
ListsAttr["Markup"] = "markup";
|
|
19
18
|
})(ListsAttr = exports.ListsAttr || (exports.ListsAttr = {}));
|
|
19
|
+
exports.Markup = {
|
|
20
|
+
bullet: {
|
|
21
|
+
values: ['-', '+', '*'],
|
|
22
|
+
default: '*',
|
|
23
|
+
},
|
|
24
|
+
ordered: {
|
|
25
|
+
values: ['.', ')'],
|
|
26
|
+
default: '.',
|
|
27
|
+
},
|
|
28
|
+
};
|
|
@@ -14,6 +14,7 @@ exports.parserTokens = {
|
|
|
14
14
|
getAttrs: (token, tokens, i) => ({
|
|
15
15
|
[const_1.ListsAttr.Tight]: listIsTight(tokens, i),
|
|
16
16
|
[const_1.ListsAttr.Bullet]: token.markup,
|
|
17
|
+
[const_1.ListsAttr.Markup]: token.markup,
|
|
17
18
|
}),
|
|
18
19
|
},
|
|
19
20
|
[const_1.ListNode.OrderedList]: {
|
|
@@ -22,6 +23,7 @@ exports.parserTokens = {
|
|
|
22
23
|
getAttrs: (token, tokens, i) => ({
|
|
23
24
|
[const_1.ListsAttr.Order]: Number(token.attrGet('start')) || 1,
|
|
24
25
|
[const_1.ListsAttr.Tight]: listIsTight(tokens, i),
|
|
26
|
+
[const_1.ListsAttr.Markup]: token.markup,
|
|
25
27
|
}),
|
|
26
28
|
},
|
|
27
29
|
};
|
|
@@ -4,7 +4,10 @@ exports.schemaSpecs = void 0;
|
|
|
4
4
|
const const_1 = require("./const");
|
|
5
5
|
exports.schemaSpecs = {
|
|
6
6
|
[const_1.ListNode.ListItem]: {
|
|
7
|
-
attrs: {
|
|
7
|
+
attrs: {
|
|
8
|
+
[const_1.ListsAttr.Tight]: { default: false },
|
|
9
|
+
[const_1.ListsAttr.Markup]: { default: null },
|
|
10
|
+
},
|
|
8
11
|
content: '(paragraph|block)+',
|
|
9
12
|
defining: true,
|
|
10
13
|
parseDOM: [{ tag: 'li' }],
|
|
@@ -19,7 +22,11 @@ exports.schemaSpecs = {
|
|
|
19
22
|
[const_1.ListNode.BulletList]: {
|
|
20
23
|
content: `${const_1.ListNode.ListItem}+`,
|
|
21
24
|
group: 'block',
|
|
22
|
-
attrs: {
|
|
25
|
+
attrs: {
|
|
26
|
+
[const_1.ListsAttr.Tight]: { default: false },
|
|
27
|
+
[const_1.ListsAttr.Bullet]: { default: const_1.Markup.bullet.default },
|
|
28
|
+
[const_1.ListsAttr.Markup]: { default: const_1.Markup.bullet.default },
|
|
29
|
+
},
|
|
23
30
|
parseDOM: [
|
|
24
31
|
{
|
|
25
32
|
tag: 'ul',
|
|
@@ -36,7 +43,11 @@ exports.schemaSpecs = {
|
|
|
36
43
|
complex: 'root',
|
|
37
44
|
},
|
|
38
45
|
[const_1.ListNode.OrderedList]: {
|
|
39
|
-
attrs: {
|
|
46
|
+
attrs: {
|
|
47
|
+
[const_1.ListsAttr.Order]: { default: 1 },
|
|
48
|
+
[const_1.ListsAttr.Tight]: { default: false },
|
|
49
|
+
[const_1.ListsAttr.Markup]: { default: const_1.Markup.ordered.default },
|
|
50
|
+
},
|
|
40
51
|
content: `${const_1.ListNode.ListItem}+`,
|
|
41
52
|
group: 'block',
|
|
42
53
|
parseDOM: [
|
|
@@ -7,15 +7,28 @@ exports.serializerTokens = {
|
|
|
7
7
|
state.renderContent(node);
|
|
8
8
|
},
|
|
9
9
|
[const_1.ListNode.BulletList]: (state, node) => {
|
|
10
|
-
state.renderList(node, ' ', (_i, li) =>
|
|
10
|
+
state.renderList(node, ' ', (_i, li) => {
|
|
11
|
+
const markup = getMarkup({ item: li, list: node, type: 'bullet' });
|
|
12
|
+
return markup + ' ';
|
|
13
|
+
});
|
|
11
14
|
},
|
|
12
15
|
[const_1.ListNode.OrderedList]: (state, node) => {
|
|
13
16
|
const start = node.attrs[const_1.ListsAttr.Order] || 1;
|
|
14
17
|
const maxW = String(start + node.childCount - 1).length;
|
|
15
18
|
const space = state.repeat(' ', maxW + 2);
|
|
16
|
-
state.renderList(node, space, (i) => {
|
|
19
|
+
state.renderList(node, space, (i, li) => {
|
|
17
20
|
const nStr = String(start + i);
|
|
18
|
-
|
|
21
|
+
const markup = getMarkup({ item: li, list: node, type: 'ordered' });
|
|
22
|
+
return state.repeat(' ', maxW - nStr.length) + nStr + markup + ' ';
|
|
19
23
|
});
|
|
20
24
|
},
|
|
21
25
|
};
|
|
26
|
+
function getMarkup({ item, list, type, }) {
|
|
27
|
+
const defs = const_1.Markup[type];
|
|
28
|
+
let value = item.attrs[const_1.ListsAttr.Markup];
|
|
29
|
+
if (!defs.values.includes(value))
|
|
30
|
+
value = list.attrs[const_1.ListsAttr.Markup];
|
|
31
|
+
if (!defs.values.includes(value))
|
|
32
|
+
value = defs.default;
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
@@ -7,6 +7,10 @@ export declare const ignoreIfCursorInsideMathInline: Command;
|
|
|
7
7
|
*/
|
|
8
8
|
export declare const removeEmptyMathInlineIfCursorIsAtBeginning: Command;
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* Handle cursor movement to the right at the boundary of a MathInline block
|
|
11
11
|
*/
|
|
12
|
-
export declare const
|
|
12
|
+
export declare const moveCursorRightOfMathInline: Command;
|
|
13
|
+
/**
|
|
14
|
+
* Handle cursor movement to the left at the boundary of a MathInline block
|
|
15
|
+
*/
|
|
16
|
+
export declare const moveCursorLeftOfMathInline: Command;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.moveCursorLeftOfMathInline = exports.moveCursorRightOfMathInline = exports.removeEmptyMathInlineIfCursorIsAtBeginning = exports.ignoreIfCursorInsideMathInline = void 0;
|
|
4
4
|
const prosemirror_state_1 = require("prosemirror-state");
|
|
5
5
|
const selection_1 = require("../../../utils/selection");
|
|
6
6
|
const const_1 = require("./const");
|
|
@@ -30,15 +30,41 @@ const removeEmptyMathInlineIfCursorIsAtBeginning = ({ tr, schema }, dispatch) =>
|
|
|
30
30
|
};
|
|
31
31
|
exports.removeEmptyMathInlineIfCursorIsAtBeginning = removeEmptyMathInlineIfCursorIsAtBeginning;
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* Handle cursor movement to the right at the boundary of a MathInline block
|
|
34
34
|
*/
|
|
35
|
-
const
|
|
35
|
+
const moveCursorRightOfMathInline = ({ tr, schema }, dispatch) => {
|
|
36
36
|
var _a;
|
|
37
37
|
const $cursor = (0, selection_1.get$Cursor)(tr.selection);
|
|
38
|
-
if (
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
if ($cursor) {
|
|
39
|
+
const mathType = (0, const_1.mathIType)(schema);
|
|
40
|
+
const isOnBeforeOfMathInline = ((_a = $cursor.nodeAfter) === null || _a === void 0 ? void 0 : _a.type) === mathType;
|
|
41
|
+
const isOnEndOfMathInline = $cursor.parentOffset === $cursor.parent.content.size &&
|
|
42
|
+
$cursor.parent.type === mathType;
|
|
43
|
+
if (isOnBeforeOfMathInline || isOnEndOfMathInline) {
|
|
44
|
+
const newPos = $cursor.pos + 1;
|
|
45
|
+
dispatch === null || dispatch === void 0 ? void 0 : dispatch(tr.setSelection(prosemirror_state_1.TextSelection.create(tr.doc, newPos)));
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return false;
|
|
50
|
+
};
|
|
51
|
+
exports.moveCursorRightOfMathInline = moveCursorRightOfMathInline;
|
|
52
|
+
/**
|
|
53
|
+
* Handle cursor movement to the left at the boundary of a MathInline block
|
|
54
|
+
*/
|
|
55
|
+
const moveCursorLeftOfMathInline = ({ tr, schema }, dispatch) => {
|
|
56
|
+
var _a;
|
|
57
|
+
const $cursor = (0, selection_1.get$Cursor)(tr.selection);
|
|
58
|
+
if ($cursor) {
|
|
59
|
+
const mathType = (0, const_1.mathIType)(schema);
|
|
60
|
+
const isOnAfterOfMathInline = ((_a = $cursor.nodeBefore) === null || _a === void 0 ? void 0 : _a.type) === mathType;
|
|
61
|
+
const isOnStartOfMathInline = $cursor.parentOffset === 0 && $cursor.parent.type === mathType;
|
|
62
|
+
if (isOnAfterOfMathInline || isOnStartOfMathInline) {
|
|
63
|
+
const newPos = $cursor.pos - 1;
|
|
64
|
+
dispatch === null || dispatch === void 0 ? void 0 : dispatch(tr.setSelection(prosemirror_state_1.TextSelection.create(tr.doc, newPos)));
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
41
67
|
}
|
|
42
68
|
return false;
|
|
43
69
|
};
|
|
44
|
-
exports.
|
|
70
|
+
exports.moveCursorLeftOfMathInline = moveCursorLeftOfMathInline;
|
|
@@ -24,7 +24,7 @@ const Math = (builder, opts) => {
|
|
|
24
24
|
builder.use(MathSpecs_1.MathSpecs);
|
|
25
25
|
builder.addKeymap(() => ({
|
|
26
26
|
Enter: commands_1.ignoreIfCursorInsideMathInline,
|
|
27
|
-
Backspace: (0, prosemirror_commands_1.chainCommands)(commands_1.
|
|
27
|
+
Backspace: (0, prosemirror_commands_1.chainCommands)(commands_1.removeEmptyMathInlineIfCursorIsAtBeginning, commands_1.moveCursorLeftOfMathInline),
|
|
28
28
|
}));
|
|
29
29
|
builder
|
|
30
30
|
.addPlugin(() => (0, view_and_edit_1.mathViewAndEditPlugin)(Object.assign(Object.assign({}, opts), { reactRenderer: builder.context.get('reactrenderer') })))
|
|
@@ -8,7 +8,6 @@ const selection_1 = require("../../../utils/selection");
|
|
|
8
8
|
const commands_1 = require("./commands");
|
|
9
9
|
const const_1 = require("./const");
|
|
10
10
|
const hint_1 = require("./hint");
|
|
11
|
-
// eslint-disable-line import/order
|
|
12
11
|
const MATH_ACTIVE_DECO = 'math_active_decoration';
|
|
13
12
|
class MathNodeView {
|
|
14
13
|
constructor(node, opts) {
|
|
@@ -162,13 +161,14 @@ class MathBlockNodeView extends MathNodeView {
|
|
|
162
161
|
exports.MathBlockNodeView = MathBlockNodeView;
|
|
163
162
|
const mathViewAndEditPlugin = (options) => new prosemirror_state_1.Plugin({
|
|
164
163
|
props: {
|
|
164
|
+
handleKeyDown: (0, prosemirror_keymap_1.keydownHandler)({
|
|
165
|
+
ArrowRight: commands_1.moveCursorRightOfMathInline,
|
|
166
|
+
ArrowLeft: commands_1.moveCursorLeftOfMathInline,
|
|
167
|
+
}),
|
|
165
168
|
nodeViews: {
|
|
166
169
|
[const_1.MathNode.Block]: (node) => new MathBlockNodeView(node, options),
|
|
167
170
|
[const_1.MathNode.Inline]: (node) => new MathInlineNodeView(node, options),
|
|
168
171
|
},
|
|
169
|
-
handleKeyDown: (0, prosemirror_keymap_1.keydownHandler)({
|
|
170
|
-
ArrowLeft: commands_1.moveCursorToEndOfMathInline,
|
|
171
|
-
}),
|
|
172
172
|
decorations: (state) => {
|
|
173
173
|
const { selection } = state;
|
|
174
174
|
if ((0, selection_1.isTextSelection)(selection)) {
|
|
@@ -10,12 +10,12 @@ const getSchemaSpecs = (opts, placeholder) => {
|
|
|
10
10
|
var _a, _b, _c, _d;
|
|
11
11
|
return ({
|
|
12
12
|
[const_1.CutNode.Cut]: {
|
|
13
|
-
attrs: { class: { default: 'yfm-cut' } },
|
|
13
|
+
attrs: { class: { default: 'yfm-cut' }, open: { default: null } },
|
|
14
14
|
content: `${const_1.CutNode.CutTitle} ${const_1.CutNode.CutContent}`,
|
|
15
15
|
group: 'block yfm-cut',
|
|
16
|
-
parseDOM: [{ tag: '
|
|
16
|
+
parseDOM: [{ tag: '.yfm-cut' }],
|
|
17
17
|
toDOM(node) {
|
|
18
|
-
return ['
|
|
18
|
+
return ['details', node.attrs, 0];
|
|
19
19
|
},
|
|
20
20
|
selectable: true,
|
|
21
21
|
allowSelection: true,
|
|
@@ -26,9 +26,9 @@ const getSchemaSpecs = (opts, placeholder) => {
|
|
|
26
26
|
attrs: { class: { default: 'yfm-cut-title' } },
|
|
27
27
|
content: 'inline*',
|
|
28
28
|
group: 'block yfm-cut',
|
|
29
|
-
parseDOM: [{ tag: '
|
|
29
|
+
parseDOM: [{ tag: '.yfm-cut-title' }],
|
|
30
30
|
toDOM(node) {
|
|
31
|
-
return ['
|
|
31
|
+
return ['summary', node.attrs, 0];
|
|
32
32
|
},
|
|
33
33
|
placeholder: {
|
|
34
34
|
content: (_b = (_a = placeholder === null || placeholder === void 0 ? void 0 : placeholder[const_1.CutNode.CutTitle]) !== null && _a !== void 0 ? _a : opts === null || opts === void 0 ? void 0 : opts.yfmCutTitlePlaceholder) !== null && _b !== void 0 ? _b : DEFAULT_PLACEHOLDERS.Title,
|
|
@@ -43,7 +43,7 @@ const getSchemaSpecs = (opts, placeholder) => {
|
|
|
43
43
|
attrs: { class: { default: 'yfm-cut-content' } },
|
|
44
44
|
content: '(block | paragraph)+',
|
|
45
45
|
group: 'block yfm-cut',
|
|
46
|
-
parseDOM: [{ tag: '
|
|
46
|
+
parseDOM: [{ tag: '.yfm-cut-content' }],
|
|
47
47
|
toDOM(node) {
|
|
48
48
|
return ['div', node.attrs, 0];
|
|
49
49
|
},
|
|
@@ -5,7 +5,7 @@ const prosemirror_state_1 = require("prosemirror-state");
|
|
|
5
5
|
const prosemirror_utils_1 = require("prosemirror-utils");
|
|
6
6
|
const const_1 = require("../const");
|
|
7
7
|
const createYfmCutNode = (schema) => (content) => {
|
|
8
|
-
return (0, const_1.cutType)(schema).create({ class: 'yfm-cut open' }, [
|
|
8
|
+
return (0, const_1.cutType)(schema).create({ class: 'yfm-cut open', open: true }, [
|
|
9
9
|
(0, const_1.cutTitleType)(schema).create(null),
|
|
10
10
|
(0, const_1.cutContentType)(schema).create(null, content),
|
|
11
11
|
]);
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
.ProseMirror.yfm .yfm-cut {
|
|
2
2
|
border: 1px dashed transparent;
|
|
3
3
|
border-radius: var(--g-border-radius-s);
|
|
4
|
+
/* TODO: Remove this after updating @diplodoc/transform to version 4.19.0 or higher */
|
|
5
|
+
/* This ensures backward compatibility with earlier versions of cut-extension */
|
|
4
6
|
}
|
|
5
7
|
.ProseMirror.yfm .yfm-cut:hover {
|
|
6
8
|
border-color: var(--g-color-line-generic);
|
|
7
9
|
}
|
|
8
10
|
.ProseMirror.yfm .yfm-cut.yfm-cut-active {
|
|
9
11
|
border-color: var(--g-color-line-generic);
|
|
12
|
+
}
|
|
13
|
+
.ProseMirror.yfm .yfm-cut .yfm-cut-title:focus {
|
|
14
|
+
outline: 0;
|
|
15
|
+
}
|
|
16
|
+
.ProseMirror.yfm .yfm-cut .yfm-cut-title {
|
|
17
|
+
list-style: none;
|
|
18
|
+
}
|
|
19
|
+
.ProseMirror.yfm .yfm-cut .yfm-cut-title::-webkit-details-marker,
|
|
20
|
+
.ProseMirror.yfm .yfm-cut .yfm-cut-title::marker {
|
|
21
|
+
display: none;
|
|
10
22
|
}
|
|
@@ -4,7 +4,7 @@ exports.YfmCutTitleNodeView = void 0;
|
|
|
4
4
|
class YfmCutTitleNodeView {
|
|
5
5
|
constructor(node) {
|
|
6
6
|
this.node = node;
|
|
7
|
-
this.dom = document.createElement('
|
|
7
|
+
this.dom = document.createElement('summary');
|
|
8
8
|
this.dom.classList.add('yfm-cut-title');
|
|
9
9
|
this.dom.replaceChildren((this.contentDOM = document.createElement('div')));
|
|
10
10
|
this.contentDOM.classList.add('g-md-yfm-cut-title-inner');
|
|
@@ -12,6 +12,7 @@ class YfmCutTitleNodeView {
|
|
|
12
12
|
// ignore clicking on the title content
|
|
13
13
|
// you can open/close yfm-cut by clicking on the arrow icon
|
|
14
14
|
e.stopPropagation();
|
|
15
|
+
e.preventDefault();
|
|
15
16
|
});
|
|
16
17
|
}
|
|
17
18
|
update(node) {
|
|
@@ -42,6 +42,7 @@ function openParentYfmCuts($pos, domAtPos) {
|
|
|
42
42
|
if ($pos.node(depth - 1).type === (0, const_1.cutType)(schema)) {
|
|
43
43
|
const { node: cutDomNode } = domAtPos($pos.start(depth - 1), 0);
|
|
44
44
|
cutDomNode.classList.add('open');
|
|
45
|
+
cutDomNode.setAttribute('open', 'true');
|
|
45
46
|
depth--;
|
|
46
47
|
}
|
|
47
48
|
}
|
|
@@ -89,9 +90,10 @@ class CutAutoOpenOnDragOver {
|
|
|
89
90
|
this._timeout = setTimeout(this._openCut.bind(this), CutAutoOpenOnDragOver.OPEN_TIMEOUT);
|
|
90
91
|
}
|
|
91
92
|
_openCut() {
|
|
92
|
-
var _a;
|
|
93
|
+
var _a, _b;
|
|
93
94
|
if (this._editorView.dragging) {
|
|
94
95
|
(_a = this._cutElem) === null || _a === void 0 ? void 0 : _a.classList.add('open');
|
|
96
|
+
(_b = this._cutElem) === null || _b === void 0 ? void 0 : _b.setAttribute('open', 'true');
|
|
95
97
|
}
|
|
96
98
|
this._clear();
|
|
97
99
|
}
|
|
@@ -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" | "heading" | "note" | "file" | "codeblock" | "checkbox" | "emoji" | "
|
|
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" | "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" | "mermaid" | "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;
|
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 '13.
|
|
5
|
+
exports.VERSION = typeof '13.24.0' !== 'undefined' ? '13.24.0' : 'unknown';
|
|
@@ -2,8 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import type { ToasterPublicMethods } from '@gravity-ui/uikit';
|
|
3
3
|
import { ClassNameProps } from '../classname';
|
|
4
4
|
import type { Editor } from './Editor';
|
|
5
|
-
import { MToolbarData, MToolbarItemData } from './config
|
|
6
|
-
import { WToolbarData, WToolbarItemData } from './config/wysiwyg';
|
|
5
|
+
import { MToolbarData, MToolbarItemData, WToolbarData, WToolbarItemData } from './config';
|
|
7
6
|
import '../styles/styles.css';
|
|
8
7
|
import './MarkdownEditorView.css';
|
|
9
8
|
export declare const cnEditorComponent: import("@bem-react/classname").ClassNameFormatter;
|
|
@@ -18,6 +17,8 @@ export declare type MarkdownEditorViewProps = ClassNameProps & {
|
|
|
18
17
|
settingsVisible?: boolean;
|
|
19
18
|
toaster: ToasterPublicMethods;
|
|
20
19
|
stickyToolbar: boolean;
|
|
20
|
+
enableSubmitInPreview?: boolean;
|
|
21
|
+
hidePreviewAfterSubmit?: boolean;
|
|
21
22
|
};
|
|
22
23
|
export declare const MarkdownEditorView: React.ForwardRefExoticComponent<ClassNameProps & {
|
|
23
24
|
editor?: Editor | undefined;
|
|
@@ -30,4 +31,6 @@ export declare const MarkdownEditorView: React.ForwardRefExoticComponent<ClassNa
|
|
|
30
31
|
settingsVisible?: boolean | undefined;
|
|
31
32
|
toaster: ToasterPublicMethods;
|
|
32
33
|
stickyToolbar: boolean;
|
|
34
|
+
enableSubmitInPreview?: boolean | undefined;
|
|
35
|
+
hidePreviewAfterSubmit?: boolean | undefined;
|
|
33
36
|
} & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -4,16 +4,13 @@ import { useEnsuredForwardedRef, useKey, useUpdate } from 'react-use';
|
|
|
4
4
|
import { cn } from '../classname';
|
|
5
5
|
import { i18n } from '../i18n/bundle';
|
|
6
6
|
import { logger } from '../logger';
|
|
7
|
-
import { useBooleanState } from '../react-utils
|
|
8
|
-
import {
|
|
9
|
-
import { useSticky } from '../react-utils/useSticky';
|
|
10
|
-
import { isMac } from '../utils/platform';
|
|
7
|
+
import { ToasterContext, useBooleanState, useSticky } from '../react-utils';
|
|
8
|
+
import { isMac } from '../utils';
|
|
11
9
|
import { HorizontalDrag } from './HorizontalDrag';
|
|
12
10
|
import { MarkupEditorView } from './MarkupEditorView';
|
|
13
11
|
import { SplitModeView } from './SplitModeView';
|
|
14
12
|
import { WysiwygEditorView } from './WysiwygEditorView';
|
|
15
|
-
import { mHiddenDataByPreset, mToolbarConfigByPreset, } from './config
|
|
16
|
-
import { wHiddenDataByPreset, wToolbarConfigByPreset, } from './config/wysiwyg';
|
|
13
|
+
import { mHiddenDataByPreset, mToolbarConfigByPreset, wHiddenDataByPreset, wToolbarConfigByPreset, } from './config';
|
|
17
14
|
import { useMarkdownEditorContext } from './context';
|
|
18
15
|
import { EditorSettings } from './settings';
|
|
19
16
|
import { stickyCn } from './sticky';
|
|
@@ -33,7 +30,7 @@ export const MarkdownEditorView = React.forwardRef((props, ref) => {
|
|
|
33
30
|
const editor = ((_a = props.editor) !== null && _a !== void 0 ? _a : context);
|
|
34
31
|
if (!editor)
|
|
35
32
|
throw new Error('[MarkdownEditorView]: an instance of the editor must be passed through the props or context');
|
|
36
|
-
const { autofocus, className, settingsVisible = true, markupToolbarConfig = mToolbarConfigByPreset[editor.preset], wysiwygToolbarConfig = wToolbarConfigByPreset[editor.preset], markupHiddenActionsConfig = mHiddenDataByPreset[editor.preset], wysiwygHiddenActionsConfig = wHiddenDataByPreset[editor.preset], toaster, stickyToolbar, } = props;
|
|
33
|
+
const { autofocus, className, settingsVisible = true, markupToolbarConfig = mToolbarConfigByPreset[editor.preset], wysiwygToolbarConfig = wToolbarConfigByPreset[editor.preset], markupHiddenActionsConfig = mHiddenDataByPreset[editor.preset], wysiwygHiddenActionsConfig = wHiddenDataByPreset[editor.preset], toaster, stickyToolbar, enableSubmitInPreview = true, hidePreviewAfterSubmit = false, } = props;
|
|
37
34
|
const rerender = useUpdate();
|
|
38
35
|
React.useLayoutEffect(() => {
|
|
39
36
|
editor.on('rerender', rerender);
|
|
@@ -63,6 +60,20 @@ export const MarkdownEditorView = React.forwardRef((props, ref) => {
|
|
|
63
60
|
useKey((e) => canRenderPreview && isPreviewKeyDown(e), () => onShowPreviewChange(!showPreview), { event: 'keydown' }, [showPreview, editorMode, onShowPreviewChange, canRenderPreview]);
|
|
64
61
|
const editorWrapperRef = useRef(null);
|
|
65
62
|
const splitModeViewWrapperRef = useRef(null);
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (showPreview) {
|
|
65
|
+
divRef.current.focus();
|
|
66
|
+
}
|
|
67
|
+
}, [divRef, showPreview]);
|
|
68
|
+
useKey((e) => enableSubmitInPreview &&
|
|
69
|
+
showPreview &&
|
|
70
|
+
isWrapperFocused(divRef) &&
|
|
71
|
+
isSubmitKeyDown(e), () => {
|
|
72
|
+
editor.emit('submit', null);
|
|
73
|
+
if (hidePreviewAfterSubmit) {
|
|
74
|
+
onShowPreviewChange(false);
|
|
75
|
+
}
|
|
76
|
+
}, { event: 'keydown' }, [hidePreviewAfterSubmit, enableSubmitInPreview, showPreview, showPreview]);
|
|
66
77
|
const settings = useMemo(() => (React.createElement(Settings, { mode: editorMode, onModeChange: onModeChange, toolbarVisibility: editor.toolbarVisible && !showPreview, onToolbarVisibilityChange: onToolbarVisibilityChange, onSplitModeChange: onSplitModeChange, splitModeEnabled: editor.splitModeEnabled, splitMode: editor.splitMode, stickyToolbar: stickyToolbar, onShowPreviewChange: onShowPreviewChange, showPreview: showPreview, renderPreviewButton: canRenderPreview })), [
|
|
67
78
|
canRenderPreview,
|
|
68
79
|
stickyToolbar,
|
|
@@ -99,7 +110,7 @@ export const MarkdownEditorView = React.forwardRef((props, ref) => {
|
|
|
99
110
|
React.createElement("div", { ref: divRef, className: b({
|
|
100
111
|
settings: settingsVisible,
|
|
101
112
|
split: markupSplitMode && editor.splitMode,
|
|
102
|
-
}, [className]) },
|
|
113
|
+
}, [className]), role: "button", tabIndex: 0 },
|
|
103
114
|
React.createElement("div", { className: b('editor-wrapper'), ref: editorWrapperRef }, showPreview ? (React.createElement(React.Fragment, null,
|
|
104
115
|
React.createElement("div", { className: b('preview-wrapper') }, (_b = editor.renderPreview) === null || _b === void 0 ? void 0 : _b.call(editor, {
|
|
105
116
|
getValue: editor.getValue,
|
|
@@ -130,3 +141,10 @@ function isPreviewKeyDown(e) {
|
|
|
130
141
|
const modKey = isMac() ? e.metaKey : e.ctrlKey;
|
|
131
142
|
return modKey && e.shiftKey && e.code === 'KeyP';
|
|
132
143
|
}
|
|
144
|
+
function isWrapperFocused(divRef) {
|
|
145
|
+
return document.activeElement === divRef.current;
|
|
146
|
+
}
|
|
147
|
+
function isSubmitKeyDown(e) {
|
|
148
|
+
const modKey = isMac() ? e.metaKey : e.ctrlKey;
|
|
149
|
+
return modKey && e.code === 'Enter';
|
|
150
|
+
}
|
|
@@ -5,10 +5,19 @@ export declare enum ListNode {
|
|
|
5
5
|
}
|
|
6
6
|
export declare enum ListsAttr {
|
|
7
7
|
Tight = "tight",
|
|
8
|
-
/**
|
|
8
|
+
/** @deprecated Use `ListsAttr.Markup` instead */
|
|
9
9
|
Bullet = "bullet",
|
|
10
10
|
/** used in ordered list only */
|
|
11
11
|
Order = "order",
|
|
12
|
-
/** used in list item only */
|
|
13
12
|
Markup = "markup"
|
|
14
13
|
}
|
|
14
|
+
export declare const Markup: {
|
|
15
|
+
bullet: {
|
|
16
|
+
values: string[];
|
|
17
|
+
default: string;
|
|
18
|
+
};
|
|
19
|
+
ordered: {
|
|
20
|
+
values: string[];
|
|
21
|
+
default: string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
@@ -7,10 +7,19 @@ export var ListNode;
|
|
|
7
7
|
export var ListsAttr;
|
|
8
8
|
(function (ListsAttr) {
|
|
9
9
|
ListsAttr["Tight"] = "tight";
|
|
10
|
-
/**
|
|
10
|
+
/** @deprecated Use `ListsAttr.Markup` instead */
|
|
11
11
|
ListsAttr["Bullet"] = "bullet";
|
|
12
12
|
/** used in ordered list only */
|
|
13
13
|
ListsAttr["Order"] = "order";
|
|
14
|
-
/** used in list item only */
|
|
15
14
|
ListsAttr["Markup"] = "markup";
|
|
16
15
|
})(ListsAttr || (ListsAttr = {}));
|
|
16
|
+
export const Markup = {
|
|
17
|
+
bullet: {
|
|
18
|
+
values: ['-', '+', '*'],
|
|
19
|
+
default: '*',
|
|
20
|
+
},
|
|
21
|
+
ordered: {
|
|
22
|
+
values: ['.', ')'],
|
|
23
|
+
default: '.',
|
|
24
|
+
},
|
|
25
|
+
};
|
|
@@ -11,6 +11,7 @@ export const parserTokens = {
|
|
|
11
11
|
getAttrs: (token, tokens, i) => ({
|
|
12
12
|
[ListsAttr.Tight]: listIsTight(tokens, i),
|
|
13
13
|
[ListsAttr.Bullet]: token.markup,
|
|
14
|
+
[ListsAttr.Markup]: token.markup,
|
|
14
15
|
}),
|
|
15
16
|
},
|
|
16
17
|
[ListNode.OrderedList]: {
|
|
@@ -19,6 +20,7 @@ export const parserTokens = {
|
|
|
19
20
|
getAttrs: (token, tokens, i) => ({
|
|
20
21
|
[ListsAttr.Order]: Number(token.attrGet('start')) || 1,
|
|
21
22
|
[ListsAttr.Tight]: listIsTight(tokens, i),
|
|
23
|
+
[ListsAttr.Markup]: token.markup,
|
|
22
24
|
}),
|
|
23
25
|
},
|
|
24
26
|
};
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { ListNode, ListsAttr } from './const';
|
|
1
|
+
import { ListNode, ListsAttr, Markup } from './const';
|
|
2
2
|
export const schemaSpecs = {
|
|
3
3
|
[ListNode.ListItem]: {
|
|
4
|
-
attrs: {
|
|
4
|
+
attrs: {
|
|
5
|
+
[ListsAttr.Tight]: { default: false },
|
|
6
|
+
[ListsAttr.Markup]: { default: null },
|
|
7
|
+
},
|
|
5
8
|
content: '(paragraph|block)+',
|
|
6
9
|
defining: true,
|
|
7
10
|
parseDOM: [{ tag: 'li' }],
|
|
@@ -16,7 +19,11 @@ export const schemaSpecs = {
|
|
|
16
19
|
[ListNode.BulletList]: {
|
|
17
20
|
content: `${ListNode.ListItem}+`,
|
|
18
21
|
group: 'block',
|
|
19
|
-
attrs: {
|
|
22
|
+
attrs: {
|
|
23
|
+
[ListsAttr.Tight]: { default: false },
|
|
24
|
+
[ListsAttr.Bullet]: { default: Markup.bullet.default },
|
|
25
|
+
[ListsAttr.Markup]: { default: Markup.bullet.default },
|
|
26
|
+
},
|
|
20
27
|
parseDOM: [
|
|
21
28
|
{
|
|
22
29
|
tag: 'ul',
|
|
@@ -33,7 +40,11 @@ export const schemaSpecs = {
|
|
|
33
40
|
complex: 'root',
|
|
34
41
|
},
|
|
35
42
|
[ListNode.OrderedList]: {
|
|
36
|
-
attrs: {
|
|
43
|
+
attrs: {
|
|
44
|
+
[ListsAttr.Order]: { default: 1 },
|
|
45
|
+
[ListsAttr.Tight]: { default: false },
|
|
46
|
+
[ListsAttr.Markup]: { default: Markup.ordered.default },
|
|
47
|
+
},
|
|
37
48
|
content: `${ListNode.ListItem}+`,
|
|
38
49
|
group: 'block',
|
|
39
50
|
parseDOM: [
|
|
@@ -1,18 +1,31 @@
|
|
|
1
|
-
import { ListNode, ListsAttr } from './const';
|
|
1
|
+
import { ListNode, ListsAttr, Markup } from './const';
|
|
2
2
|
export const serializerTokens = {
|
|
3
3
|
[ListNode.ListItem]: (state, node) => {
|
|
4
4
|
state.renderContent(node);
|
|
5
5
|
},
|
|
6
6
|
[ListNode.BulletList]: (state, node) => {
|
|
7
|
-
state.renderList(node, ' ', (_i, li) =>
|
|
7
|
+
state.renderList(node, ' ', (_i, li) => {
|
|
8
|
+
const markup = getMarkup({ item: li, list: node, type: 'bullet' });
|
|
9
|
+
return markup + ' ';
|
|
10
|
+
});
|
|
8
11
|
},
|
|
9
12
|
[ListNode.OrderedList]: (state, node) => {
|
|
10
13
|
const start = node.attrs[ListsAttr.Order] || 1;
|
|
11
14
|
const maxW = String(start + node.childCount - 1).length;
|
|
12
15
|
const space = state.repeat(' ', maxW + 2);
|
|
13
|
-
state.renderList(node, space, (i) => {
|
|
16
|
+
state.renderList(node, space, (i, li) => {
|
|
14
17
|
const nStr = String(start + i);
|
|
15
|
-
|
|
18
|
+
const markup = getMarkup({ item: li, list: node, type: 'ordered' });
|
|
19
|
+
return state.repeat(' ', maxW - nStr.length) + nStr + markup + ' ';
|
|
16
20
|
});
|
|
17
21
|
},
|
|
18
22
|
};
|
|
23
|
+
function getMarkup({ item, list, type, }) {
|
|
24
|
+
const defs = Markup[type];
|
|
25
|
+
let value = item.attrs[ListsAttr.Markup];
|
|
26
|
+
if (!defs.values.includes(value))
|
|
27
|
+
value = list.attrs[ListsAttr.Markup];
|
|
28
|
+
if (!defs.values.includes(value))
|
|
29
|
+
value = defs.default;
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
@@ -7,6 +7,10 @@ export declare const ignoreIfCursorInsideMathInline: Command;
|
|
|
7
7
|
*/
|
|
8
8
|
export declare const removeEmptyMathInlineIfCursorIsAtBeginning: Command;
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* Handle cursor movement to the right at the boundary of a MathInline block
|
|
11
11
|
*/
|
|
12
|
-
export declare const
|
|
12
|
+
export declare const moveCursorRightOfMathInline: Command;
|
|
13
|
+
/**
|
|
14
|
+
* Handle cursor movement to the left at the boundary of a MathInline block
|
|
15
|
+
*/
|
|
16
|
+
export declare const moveCursorLeftOfMathInline: Command;
|
|
@@ -25,14 +25,39 @@ export const removeEmptyMathInlineIfCursorIsAtBeginning = ({ tr, schema }, dispa
|
|
|
25
25
|
return false;
|
|
26
26
|
};
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
28
|
+
* Handle cursor movement to the right at the boundary of a MathInline block
|
|
29
29
|
*/
|
|
30
|
-
export const
|
|
30
|
+
export const moveCursorRightOfMathInline = ({ tr, schema }, dispatch) => {
|
|
31
31
|
var _a;
|
|
32
32
|
const $cursor = get$Cursor(tr.selection);
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
if ($cursor) {
|
|
34
|
+
const mathType = mathIType(schema);
|
|
35
|
+
const isOnBeforeOfMathInline = ((_a = $cursor.nodeAfter) === null || _a === void 0 ? void 0 : _a.type) === mathType;
|
|
36
|
+
const isOnEndOfMathInline = $cursor.parentOffset === $cursor.parent.content.size &&
|
|
37
|
+
$cursor.parent.type === mathType;
|
|
38
|
+
if (isOnBeforeOfMathInline || isOnEndOfMathInline) {
|
|
39
|
+
const newPos = $cursor.pos + 1;
|
|
40
|
+
dispatch === null || dispatch === void 0 ? void 0 : dispatch(tr.setSelection(TextSelection.create(tr.doc, newPos)));
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Handle cursor movement to the left at the boundary of a MathInline block
|
|
48
|
+
*/
|
|
49
|
+
export const moveCursorLeftOfMathInline = ({ tr, schema }, dispatch) => {
|
|
50
|
+
var _a;
|
|
51
|
+
const $cursor = get$Cursor(tr.selection);
|
|
52
|
+
if ($cursor) {
|
|
53
|
+
const mathType = mathIType(schema);
|
|
54
|
+
const isOnAfterOfMathInline = ((_a = $cursor.nodeBefore) === null || _a === void 0 ? void 0 : _a.type) === mathType;
|
|
55
|
+
const isOnStartOfMathInline = $cursor.parentOffset === 0 && $cursor.parent.type === mathType;
|
|
56
|
+
if (isOnAfterOfMathInline || isOnStartOfMathInline) {
|
|
57
|
+
const newPos = $cursor.pos - 1;
|
|
58
|
+
dispatch === null || dispatch === void 0 ? void 0 : dispatch(tr.setSelection(TextSelection.create(tr.doc, newPos)));
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
36
61
|
}
|
|
37
62
|
return false;
|
|
38
63
|
};
|
|
@@ -4,7 +4,7 @@ import { hasParentNodeOfType } from 'prosemirror-utils';
|
|
|
4
4
|
import { inlineNodeInputRule, textblockTypeInputRule } from '../../../utils/inputrules';
|
|
5
5
|
import { isTextSelection } from '../../../utils/selection';
|
|
6
6
|
import { MathSpecs } from './MathSpecs';
|
|
7
|
-
import { ignoreIfCursorInsideMathInline,
|
|
7
|
+
import { ignoreIfCursorInsideMathInline, moveCursorLeftOfMathInline, removeEmptyMathInlineIfCursorIsAtBeginning, } from './commands';
|
|
8
8
|
import { mathBType, mathIType } from './const';
|
|
9
9
|
import { mathViewAndEditPlugin } from './view-and-edit';
|
|
10
10
|
import './index.css';
|
|
@@ -17,7 +17,7 @@ export const Math = (builder, opts) => {
|
|
|
17
17
|
builder.use(MathSpecs);
|
|
18
18
|
builder.addKeymap(() => ({
|
|
19
19
|
Enter: ignoreIfCursorInsideMathInline,
|
|
20
|
-
Backspace: chainCommands(
|
|
20
|
+
Backspace: chainCommands(removeEmptyMathInlineIfCursorIsAtBeginning, moveCursorLeftOfMathInline),
|
|
21
21
|
}));
|
|
22
22
|
builder
|
|
23
23
|
.addPlugin(() => mathViewAndEditPlugin(Object.assign(Object.assign({}, opts), { reactRenderer: builder.context.get('reactrenderer') })))
|
|
@@ -2,10 +2,10 @@ import { keydownHandler } from 'prosemirror-keymap';
|
|
|
2
2
|
import { Plugin } from 'prosemirror-state';
|
|
3
3
|
import { Decoration, DecorationSet } from 'prosemirror-view';
|
|
4
4
|
import { isTextSelection } from '../../../utils/selection';
|
|
5
|
-
import {
|
|
5
|
+
import { moveCursorLeftOfMathInline, moveCursorRightOfMathInline } from './commands';
|
|
6
6
|
import { CLASSNAMES, MathNode } from './const';
|
|
7
7
|
import { b, renderMathHint } from './hint';
|
|
8
|
-
import './view-and-edit.css';
|
|
8
|
+
import './view-and-edit.css';
|
|
9
9
|
const MATH_ACTIVE_DECO = 'math_active_decoration';
|
|
10
10
|
export class MathNodeView {
|
|
11
11
|
constructor(node, opts) {
|
|
@@ -156,13 +156,14 @@ export class MathBlockNodeView extends MathNodeView {
|
|
|
156
156
|
}
|
|
157
157
|
export const mathViewAndEditPlugin = (options) => new Plugin({
|
|
158
158
|
props: {
|
|
159
|
+
handleKeyDown: keydownHandler({
|
|
160
|
+
ArrowRight: moveCursorRightOfMathInline,
|
|
161
|
+
ArrowLeft: moveCursorLeftOfMathInline,
|
|
162
|
+
}),
|
|
159
163
|
nodeViews: {
|
|
160
164
|
[MathNode.Block]: (node) => new MathBlockNodeView(node, options),
|
|
161
165
|
[MathNode.Inline]: (node) => new MathInlineNodeView(node, options),
|
|
162
166
|
},
|
|
163
|
-
handleKeyDown: keydownHandler({
|
|
164
|
-
ArrowLeft: moveCursorToEndOfMathInline,
|
|
165
|
-
}),
|
|
166
167
|
decorations: (state) => {
|
|
167
168
|
const { selection } = state;
|
|
168
169
|
if (isTextSelection(selection)) {
|
|
@@ -7,12 +7,12 @@ export const getSchemaSpecs = (opts, placeholder) => {
|
|
|
7
7
|
var _a, _b, _c, _d;
|
|
8
8
|
return ({
|
|
9
9
|
[CutNode.Cut]: {
|
|
10
|
-
attrs: { class: { default: 'yfm-cut' } },
|
|
10
|
+
attrs: { class: { default: 'yfm-cut' }, open: { default: null } },
|
|
11
11
|
content: `${CutNode.CutTitle} ${CutNode.CutContent}`,
|
|
12
12
|
group: 'block yfm-cut',
|
|
13
|
-
parseDOM: [{ tag: '
|
|
13
|
+
parseDOM: [{ tag: '.yfm-cut' }],
|
|
14
14
|
toDOM(node) {
|
|
15
|
-
return ['
|
|
15
|
+
return ['details', node.attrs, 0];
|
|
16
16
|
},
|
|
17
17
|
selectable: true,
|
|
18
18
|
allowSelection: true,
|
|
@@ -23,9 +23,9 @@ export const getSchemaSpecs = (opts, placeholder) => {
|
|
|
23
23
|
attrs: { class: { default: 'yfm-cut-title' } },
|
|
24
24
|
content: 'inline*',
|
|
25
25
|
group: 'block yfm-cut',
|
|
26
|
-
parseDOM: [{ tag: '
|
|
26
|
+
parseDOM: [{ tag: '.yfm-cut-title' }],
|
|
27
27
|
toDOM(node) {
|
|
28
|
-
return ['
|
|
28
|
+
return ['summary', node.attrs, 0];
|
|
29
29
|
},
|
|
30
30
|
placeholder: {
|
|
31
31
|
content: (_b = (_a = placeholder === null || placeholder === void 0 ? void 0 : placeholder[CutNode.CutTitle]) !== null && _a !== void 0 ? _a : opts === null || opts === void 0 ? void 0 : opts.yfmCutTitlePlaceholder) !== null && _b !== void 0 ? _b : DEFAULT_PLACEHOLDERS.Title,
|
|
@@ -40,7 +40,7 @@ export const getSchemaSpecs = (opts, placeholder) => {
|
|
|
40
40
|
attrs: { class: { default: 'yfm-cut-content' } },
|
|
41
41
|
content: '(block | paragraph)+',
|
|
42
42
|
group: 'block yfm-cut',
|
|
43
|
-
parseDOM: [{ tag: '
|
|
43
|
+
parseDOM: [{ tag: '.yfm-cut-content' }],
|
|
44
44
|
toDOM(node) {
|
|
45
45
|
return ['div', node.attrs, 0];
|
|
46
46
|
},
|
|
@@ -2,7 +2,7 @@ import { TextSelection } from 'prosemirror-state';
|
|
|
2
2
|
import { findParentNodeClosestToPos } from 'prosemirror-utils';
|
|
3
3
|
import { cutContentType, cutTitleType, cutType } from '../const';
|
|
4
4
|
const createYfmCutNode = (schema) => (content) => {
|
|
5
|
-
return cutType(schema).create({ class: 'yfm-cut open' }, [
|
|
5
|
+
return cutType(schema).create({ class: 'yfm-cut open', open: true }, [
|
|
6
6
|
cutTitleType(schema).create(null),
|
|
7
7
|
cutContentType(schema).create(null, content),
|
|
8
8
|
]);
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
.ProseMirror.yfm .yfm-cut {
|
|
2
2
|
border: 1px dashed transparent;
|
|
3
3
|
border-radius: var(--g-border-radius-s);
|
|
4
|
+
/* TODO: Remove this after updating @diplodoc/transform to version 4.19.0 or higher */
|
|
5
|
+
/* This ensures backward compatibility with earlier versions of cut-extension */
|
|
4
6
|
}
|
|
5
7
|
.ProseMirror.yfm .yfm-cut:hover {
|
|
6
8
|
border-color: var(--g-color-line-generic);
|
|
7
9
|
}
|
|
8
10
|
.ProseMirror.yfm .yfm-cut.yfm-cut-active {
|
|
9
11
|
border-color: var(--g-color-line-generic);
|
|
12
|
+
}
|
|
13
|
+
.ProseMirror.yfm .yfm-cut .yfm-cut-title:focus {
|
|
14
|
+
outline: 0;
|
|
15
|
+
}
|
|
16
|
+
.ProseMirror.yfm .yfm-cut .yfm-cut-title {
|
|
17
|
+
list-style: none;
|
|
18
|
+
}
|
|
19
|
+
.ProseMirror.yfm .yfm-cut .yfm-cut-title::-webkit-details-marker,
|
|
20
|
+
.ProseMirror.yfm .yfm-cut .yfm-cut-title::marker {
|
|
21
|
+
display: none;
|
|
10
22
|
}
|
|
@@ -2,7 +2,7 @@ import './yfm-cut-title.css';
|
|
|
2
2
|
export class YfmCutTitleNodeView {
|
|
3
3
|
constructor(node) {
|
|
4
4
|
this.node = node;
|
|
5
|
-
this.dom = document.createElement('
|
|
5
|
+
this.dom = document.createElement('summary');
|
|
6
6
|
this.dom.classList.add('yfm-cut-title');
|
|
7
7
|
this.dom.replaceChildren((this.contentDOM = document.createElement('div')));
|
|
8
8
|
this.contentDOM.classList.add('g-md-yfm-cut-title-inner');
|
|
@@ -10,6 +10,7 @@ export class YfmCutTitleNodeView {
|
|
|
10
10
|
// ignore clicking on the title content
|
|
11
11
|
// you can open/close yfm-cut by clicking on the arrow icon
|
|
12
12
|
e.stopPropagation();
|
|
13
|
+
e.preventDefault();
|
|
13
14
|
});
|
|
14
15
|
}
|
|
15
16
|
update(node) {
|
|
@@ -38,6 +38,7 @@ function openParentYfmCuts($pos, domAtPos) {
|
|
|
38
38
|
if ($pos.node(depth - 1).type === cutType(schema)) {
|
|
39
39
|
const { node: cutDomNode } = domAtPos($pos.start(depth - 1), 0);
|
|
40
40
|
cutDomNode.classList.add('open');
|
|
41
|
+
cutDomNode.setAttribute('open', 'true');
|
|
41
42
|
depth--;
|
|
42
43
|
}
|
|
43
44
|
}
|
|
@@ -85,9 +86,10 @@ class CutAutoOpenOnDragOver {
|
|
|
85
86
|
this._timeout = setTimeout(this._openCut.bind(this), CutAutoOpenOnDragOver.OPEN_TIMEOUT);
|
|
86
87
|
}
|
|
87
88
|
_openCut() {
|
|
88
|
-
var _a;
|
|
89
|
+
var _a, _b;
|
|
89
90
|
if (this._editorView.dragging) {
|
|
90
91
|
(_a = this._cutElem) === null || _a === void 0 ? void 0 : _a.classList.add('open');
|
|
92
|
+
(_b = this._cutElem) === null || _b === void 0 ? void 0 : _b.setAttribute('open', 'true');
|
|
91
93
|
}
|
|
92
94
|
this._clear();
|
|
93
95
|
}
|
|
@@ -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" | "heading" | "note" | "file" | "codeblock" | "checkbox" | "emoji" | "
|
|
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" | "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" | "mermaid" | "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;
|
package/build/esm/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** During build process, the current version will be injected here */
|
|
2
|
-
export const VERSION = typeof '13.
|
|
2
|
+
export const VERSION = typeof '13.24.0' !== 'undefined' ? '13.24.0' : 'unknown';
|
package/build/styles.css
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
.g-md-editor-component {
|
|
2
2
|
display: flex;
|
|
3
3
|
height: 100%;
|
|
4
|
+
outline: none;
|
|
4
5
|
}
|
|
5
6
|
.g-md-editor-component_split_vertical {
|
|
6
7
|
display: grid;
|
|
@@ -1047,6 +1048,8 @@ body :has(.g-md-resizable_resizing) {
|
|
|
1047
1048
|
.ProseMirror.yfm .yfm-cut {
|
|
1048
1049
|
border: 1px dashed transparent;
|
|
1049
1050
|
border-radius: var(--g-border-radius-s);
|
|
1051
|
+
/* TODO: Remove this after updating @diplodoc/transform to version 4.19.0 or higher */
|
|
1052
|
+
/* This ensures backward compatibility with earlier versions of cut-extension */
|
|
1050
1053
|
}
|
|
1051
1054
|
.ProseMirror.yfm .yfm-cut:hover {
|
|
1052
1055
|
border-color: var(--g-color-line-generic);
|
|
@@ -1054,6 +1057,16 @@ body :has(.g-md-resizable_resizing) {
|
|
|
1054
1057
|
.ProseMirror.yfm .yfm-cut.yfm-cut-active {
|
|
1055
1058
|
border-color: var(--g-color-line-generic);
|
|
1056
1059
|
}
|
|
1060
|
+
.ProseMirror.yfm .yfm-cut .yfm-cut-title:focus {
|
|
1061
|
+
outline: 0;
|
|
1062
|
+
}
|
|
1063
|
+
.ProseMirror.yfm .yfm-cut .yfm-cut-title {
|
|
1064
|
+
list-style: none;
|
|
1065
|
+
}
|
|
1066
|
+
.ProseMirror.yfm .yfm-cut .yfm-cut-title::-webkit-details-marker,
|
|
1067
|
+
.ProseMirror.yfm .yfm-cut .yfm-cut-title::marker {
|
|
1068
|
+
display: none;
|
|
1069
|
+
}
|
|
1057
1070
|
.yfm-editor .yfm-file {
|
|
1058
1071
|
pointer-events: none;
|
|
1059
1072
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gravity-ui/markdown-editor",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.24.0",
|
|
4
4
|
"description": "Markdown wysiwyg and markup editor",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -204,7 +204,7 @@
|
|
|
204
204
|
"@diplodoc/html-extension": "2.3.2",
|
|
205
205
|
"@diplodoc/latex-extension": "1.0.3",
|
|
206
206
|
"@diplodoc/mermaid-extension": "1.2.1",
|
|
207
|
-
"@diplodoc/transform": "4.
|
|
207
|
+
"@diplodoc/transform": "4.26.0",
|
|
208
208
|
"@gravity-ui/components": "3.0.0",
|
|
209
209
|
"@gravity-ui/eslint-config": "3.1.1",
|
|
210
210
|
"@gravity-ui/prettier-config": "1.1.0",
|
|
@@ -279,7 +279,7 @@
|
|
|
279
279
|
"@diplodoc/html-extension": "2.3.2",
|
|
280
280
|
"@diplodoc/latex-extension": "^1.0.3",
|
|
281
281
|
"@diplodoc/mermaid-extension": "^1.0.0",
|
|
282
|
-
"@diplodoc/transform": ">=4.5.0
|
|
282
|
+
"@diplodoc/transform": ">=4.5.0 <=4.26.0",
|
|
283
283
|
"@gravity-ui/components": "^3.0.0",
|
|
284
284
|
"@gravity-ui/uikit": "^6.11.0",
|
|
285
285
|
"highlight.js": "^11.8.0",
|