@gravity-ui/markdown-editor 14.11.1 → 14.12.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/Editor.js +9 -2
- package/build/cjs/bundle/MarkupManager.d.ts +54 -0
- package/build/cjs/bundle/MarkupManager.js +68 -0
- package/build/cjs/bundle/config/dynamicModifiers.d.ts +3 -0
- package/build/cjs/bundle/config/dynamicModifiers.js +76 -0
- package/build/cjs/bundle/config/markup.js +7 -0
- package/build/cjs/bundle/config/previews/ActionPreview.css +45 -0
- package/build/cjs/bundle/config/previews/ActionPreview.d.ts +4 -0
- package/build/cjs/bundle/config/previews/ActionPreview.js +11 -0
- package/build/cjs/bundle/config/previews/HeadingPreview.d.ts +5 -0
- package/build/cjs/bundle/config/previews/HeadingPreview.js +16 -0
- package/build/cjs/bundle/config/previews/TextPreview.d.ts +1 -0
- package/build/cjs/bundle/config/previews/TextPreview.js +14 -0
- package/build/cjs/bundle/config/w-heading-config.js +11 -0
- package/build/cjs/bundle/toolbar/utils/toolbarsConfigs.js +2 -1
- package/build/cjs/bundle/types.d.ts +11 -0
- package/build/cjs/core/Editor.d.ts +2 -2
- package/build/cjs/core/Editor.js +16 -1
- package/build/cjs/core/ExtensionsManager.d.ts +12 -2
- package/build/cjs/core/ExtensionsManager.js +29 -13
- package/build/cjs/core/ParserTokensRegistry.d.ts +2 -1
- package/build/cjs/core/ParserTokensRegistry.js +2 -2
- package/build/cjs/core/SchemaDynamicModifier.d.ts +3 -0
- package/build/cjs/core/SchemaDynamicModifier.js +25 -0
- package/build/cjs/core/SchemaSpecRegistry.d.ts +2 -1
- package/build/cjs/core/SchemaSpecRegistry.js +9 -4
- package/build/cjs/core/SerializerTokensRegistry.d.ts +2 -1
- package/build/cjs/core/SerializerTokensRegistry.js +2 -2
- package/build/cjs/core/index.d.ts +2 -0
- package/build/cjs/core/markdown/MarkdownParser.d.ts +7 -3
- package/build/cjs/core/markdown/MarkdownParser.js +85 -16
- package/build/cjs/core/markdown/MarkdownSerializer.d.ts +4 -2
- package/build/cjs/core/markdown/MarkdownSerializer.js +16 -6
- package/build/cjs/core/markdown/MarkdownSerializerDynamicModifier.d.ts +1 -0
- package/build/cjs/core/markdown/MarkdownSerializerDynamicModifier.js +47 -0
- package/build/cjs/core/types/dynamicModifiers.d.ts +1 -0
- package/build/cjs/core/types/dynamicModifiers.js +2 -0
- package/build/cjs/core/utils/dynamicModifiers.d.ts +9 -0
- package/build/cjs/core/utils/dynamicModifiers.js +48 -0
- package/build/cjs/extensions/behavior/CommandMenu/component.d.ts +1 -1
- package/build/cjs/extensions/behavior/CommandMenu/component.js +10 -8
- package/build/cjs/i18n/action-previews/en.json +5 -0
- package/build/cjs/i18n/action-previews/index.d.ts +7 -0
- package/build/cjs/i18n/action-previews/index.js +9 -0
- package/build/cjs/i18n/action-previews/ru.json +5 -0
- package/build/cjs/modules/toolbars/items.js +9 -0
- package/build/cjs/modules/toolbars/types.d.ts +1 -0
- package/build/cjs/toolbar/PreviewTooltip.css +8 -0
- package/build/cjs/toolbar/PreviewTooltip.d.ts +7 -0
- package/build/cjs/toolbar/PreviewTooltip.js +13 -0
- package/build/cjs/toolbar/ToolbarListButton.js +23 -18
- package/build/cjs/toolbar/types.d.ts +1 -0
- package/build/cjs/version.js +1 -1
- package/build/esm/bundle/Editor.js +9 -2
- package/build/esm/bundle/MarkupManager.d.ts +54 -0
- package/build/esm/bundle/MarkupManager.js +64 -0
- package/build/esm/bundle/config/dynamicModifiers.d.ts +3 -0
- package/build/esm/bundle/config/dynamicModifiers.js +72 -0
- package/build/esm/bundle/config/markup.js +7 -0
- package/build/esm/bundle/config/previews/ActionPreview.css +45 -0
- package/build/esm/bundle/config/previews/ActionPreview.d.ts +5 -0
- package/build/esm/bundle/config/previews/ActionPreview.js +7 -0
- package/build/esm/bundle/config/previews/HeadingPreview.d.ts +6 -0
- package/build/esm/bundle/config/previews/HeadingPreview.js +12 -0
- package/build/esm/bundle/config/previews/TextPreview.d.ts +2 -0
- package/build/esm/bundle/config/previews/TextPreview.js +10 -0
- package/build/esm/bundle/config/w-heading-config.js +10 -0
- package/build/esm/bundle/toolbar/utils/toolbarsConfigs.js +2 -1
- package/build/esm/bundle/types.d.ts +11 -0
- package/build/esm/core/Editor.d.ts +2 -2
- package/build/esm/core/Editor.js +16 -1
- package/build/esm/core/ExtensionsManager.d.ts +12 -2
- package/build/esm/core/ExtensionsManager.js +29 -13
- package/build/esm/core/ParserTokensRegistry.d.ts +2 -1
- package/build/esm/core/ParserTokensRegistry.js +2 -2
- package/build/esm/core/SchemaDynamicModifier.d.ts +3 -0
- package/build/esm/core/SchemaDynamicModifier.js +21 -0
- package/build/esm/core/SchemaSpecRegistry.d.ts +2 -1
- package/build/esm/core/SchemaSpecRegistry.js +9 -4
- package/build/esm/core/SerializerTokensRegistry.d.ts +2 -1
- package/build/esm/core/SerializerTokensRegistry.js +2 -2
- package/build/esm/core/index.d.ts +2 -0
- package/build/esm/core/markdown/MarkdownParser.d.ts +7 -3
- package/build/esm/core/markdown/MarkdownParser.js +83 -15
- package/build/esm/core/markdown/MarkdownSerializer.d.ts +4 -2
- package/build/esm/core/markdown/MarkdownSerializer.js +16 -6
- package/build/esm/core/markdown/MarkdownSerializerDynamicModifier.d.ts +1 -0
- package/build/esm/core/markdown/MarkdownSerializerDynamicModifier.js +43 -0
- package/build/esm/core/types/dynamicModifiers.d.ts +1 -0
- package/build/esm/core/types/dynamicModifiers.js +1 -0
- package/build/esm/core/utils/dynamicModifiers.d.ts +9 -0
- package/build/esm/core/utils/dynamicModifiers.js +44 -0
- package/build/esm/extensions/behavior/CommandMenu/component.d.ts +1 -1
- package/build/esm/extensions/behavior/CommandMenu/component.js +10 -8
- package/build/esm/i18n/action-previews/en.json +5 -0
- package/build/esm/i18n/action-previews/index.d.ts +7 -0
- package/build/esm/i18n/action-previews/index.js +5 -0
- package/build/esm/i18n/action-previews/ru.json +5 -0
- package/build/esm/modules/toolbars/items.js +9 -0
- package/build/esm/modules/toolbars/types.d.ts +1 -0
- package/build/esm/toolbar/PreviewTooltip.css +8 -0
- package/build/esm/toolbar/PreviewTooltip.d.ts +8 -0
- package/build/esm/toolbar/PreviewTooltip.js +9 -0
- package/build/esm/toolbar/ToolbarListButton.js +23 -18
- package/build/esm/toolbar/types.d.ts +1 -0
- package/build/esm/version.js +1 -1
- package/build/styles.css +53 -0
- package/package.json +5 -4
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
export class MarkdownSerializer {
|
|
2
|
-
constructor(nodes: any, marks: any);
|
|
2
|
+
constructor(nodes: any, marks: any, dynamicModifier: any);
|
|
3
3
|
nodes: any;
|
|
4
4
|
marks: any;
|
|
5
|
+
dynamicModifier: any;
|
|
5
6
|
serialize(content: any, options: any): string;
|
|
6
7
|
containsNode(nodeName: any): boolean;
|
|
7
8
|
containsMark(markName: any): boolean;
|
|
8
9
|
}
|
|
9
10
|
export class MarkdownSerializerState {
|
|
10
|
-
constructor(nodes: any, marks: any, options: any);
|
|
11
|
+
constructor(nodes: any, marks: any, options: any, dynamicModifier: any);
|
|
11
12
|
nodes: any;
|
|
12
13
|
marks: any;
|
|
13
14
|
delim: string;
|
|
@@ -20,6 +21,7 @@ export class MarkdownSerializerState {
|
|
|
20
21
|
/** @type {Boolean} */
|
|
21
22
|
escapeWhitespace: boolean;
|
|
22
23
|
options: any;
|
|
24
|
+
dynamicModifier: any;
|
|
23
25
|
setNoAutoBlank(): void;
|
|
24
26
|
unsetNoAutoBlank(): void;
|
|
25
27
|
flushClose(size: any): void;
|
|
@@ -36,18 +36,19 @@ export class MarkdownSerializer {
|
|
|
36
36
|
// outside the marks. This is necessary for emphasis marks as
|
|
37
37
|
// CommonMark does not permit enclosing whitespace inside emphasis
|
|
38
38
|
// marks, see: http://spec.commonmark.org/0.26/#example-330
|
|
39
|
-
constructor(nodes, marks) {
|
|
39
|
+
constructor(nodes, marks, dynamicModifier) {
|
|
40
40
|
// :: Object<(MarkdownSerializerState, Node)> The node serializer
|
|
41
41
|
// functions for this serializer.
|
|
42
42
|
this.nodes = nodes;
|
|
43
43
|
// :: Object The mark serializer info.
|
|
44
44
|
this.marks = marks;
|
|
45
|
+
this.dynamicModifier = dynamicModifier;
|
|
45
46
|
}
|
|
46
47
|
// :: (Node, ?Object) → string
|
|
47
48
|
// Serialize the content of the given node to
|
|
48
49
|
// [CommonMark](http://commonmark.org/).
|
|
49
50
|
serialize(content, options) {
|
|
50
|
-
const state = new MarkdownSerializerState(this.nodes, this.marks, options);
|
|
51
|
+
const state = new MarkdownSerializerState(this.nodes, this.marks, options, this.dynamicModifier);
|
|
51
52
|
state.renderContent(content);
|
|
52
53
|
return state.out;
|
|
53
54
|
}
|
|
@@ -65,7 +66,7 @@ export class MarkdownSerializer {
|
|
|
65
66
|
// node and mark serialization methods (see `toMarkdown`).
|
|
66
67
|
// prettier-ignore
|
|
67
68
|
export class MarkdownSerializerState {
|
|
68
|
-
constructor(nodes, marks, options) {
|
|
69
|
+
constructor(nodes, marks, options, dynamicModifier) {
|
|
69
70
|
this.nodes = nodes;
|
|
70
71
|
this.marks = marks;
|
|
71
72
|
this.delim = this.out = '';
|
|
@@ -83,6 +84,7 @@ export class MarkdownSerializerState {
|
|
|
83
84
|
// on a node level by specifying a tight attribute on the node.
|
|
84
85
|
// Defaults to false.
|
|
85
86
|
this.options = options || {};
|
|
87
|
+
this.dynamicModifier = dynamicModifier;
|
|
86
88
|
if (typeof this.options.tightLists === 'undefined') {
|
|
87
89
|
this.options.tightLists = false;
|
|
88
90
|
}
|
|
@@ -173,11 +175,19 @@ export class MarkdownSerializerState {
|
|
|
173
175
|
// :: (Node)
|
|
174
176
|
// Render the given node as a block.
|
|
175
177
|
render(node, parent, index) {
|
|
176
|
-
if (typeof parent === 'number')
|
|
178
|
+
if (typeof parent === 'number') {
|
|
177
179
|
throw new Error('!');
|
|
178
|
-
|
|
180
|
+
}
|
|
181
|
+
if (!this.nodes[node.type.name]) {
|
|
179
182
|
throw new Error('Token type `' + node.type.name + '` not supported by Markdown renderer');
|
|
180
|
-
|
|
183
|
+
}
|
|
184
|
+
const callback = this.nodes[node.type.name];
|
|
185
|
+
if (this.dynamicModifier) {
|
|
186
|
+
this.dynamicModifier.processNode(this, node, parent, index, callback);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
callback(this, node, parent, index);
|
|
190
|
+
}
|
|
181
191
|
}
|
|
182
192
|
// :: (Node)
|
|
183
193
|
// Render the contents of `parent` as block nodes.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Class MarkdownSerializerDynamicModifier
|
|
3
|
+
*
|
|
4
|
+
* Provides a mechanism for dynamic modification of node serialization during conversion of ProseMirror nodes
|
|
5
|
+
* to a markdown-like format. It allows sequential processing of nodes by applying a series of custom handlers:
|
|
6
|
+
*
|
|
7
|
+
* - `processNode`: An array of handlers that process nodes sequentially, each modifying the output.
|
|
8
|
+
*
|
|
9
|
+
* Example:
|
|
10
|
+
* ```ts
|
|
11
|
+
* const serializerModifier = new MarkdownSerializerDynamicModifier({
|
|
12
|
+
* paragraph: {
|
|
13
|
+
* processNode: [
|
|
14
|
+
* (state, node, parent, index, callback) => {
|
|
15
|
+
* // Custom modifications can be performed here.
|
|
16
|
+
* callback(state, node, parent, index);
|
|
17
|
+
* },
|
|
18
|
+
* ],
|
|
19
|
+
* },
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* This class extends the functionality of a MarkdownSerializer for scenarios such as:
|
|
24
|
+
* - Customizing the serialization output.
|
|
25
|
+
* - Logging or modifying node content during serialization.
|
|
26
|
+
*/
|
|
27
|
+
/** @internal */
|
|
28
|
+
export class MarkdownSerializerDynamicModifier {
|
|
29
|
+
constructor(config) {
|
|
30
|
+
this.nodeProcessors = new Map(Object.entries(config));
|
|
31
|
+
}
|
|
32
|
+
processNode(state, node, parent, index, callback) {
|
|
33
|
+
const nodeType = this.nodeProcessors.get(node.type.name);
|
|
34
|
+
if (!nodeType || !nodeType.processNode || nodeType.processNode.length === 0) {
|
|
35
|
+
callback(state, node, parent, index);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
nodeType.processNode.forEach((process) => {
|
|
39
|
+
process(state, node, parent, index, callback);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SchemaDynamicModifierConfig } from '../SchemaDynamicModifier';
|
|
2
|
+
import { MarkdownParserDynamicModifierConfig } from '../markdown/MarkdownParser';
|
|
3
|
+
import { MarkdownSerializerDynamicModifierConfig } from '../markdown/MarkdownSerializerDynamicModifier';
|
|
4
|
+
import { DynamicModifiers } from '../types/dynamicModifiers';
|
|
5
|
+
export declare function convertDynamicModifiersConfigs(modifiers: DynamicModifiers[]): {
|
|
6
|
+
parser: MarkdownParserDynamicModifierConfig;
|
|
7
|
+
schema: SchemaDynamicModifierConfig;
|
|
8
|
+
serializer: MarkdownSerializerDynamicModifierConfig;
|
|
9
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export function convertDynamicModifiersConfigs(modifiers) {
|
|
2
|
+
const parser = {};
|
|
3
|
+
const schema = {};
|
|
4
|
+
const serializer = {};
|
|
5
|
+
modifiers.forEach((modifier) => {
|
|
6
|
+
var _a, _b, _c, _d;
|
|
7
|
+
switch (modifier.type) {
|
|
8
|
+
case 'parserToken': {
|
|
9
|
+
const { tokenName, process } = modifier;
|
|
10
|
+
parser[tokenName] = parser[tokenName] || {};
|
|
11
|
+
parser[tokenName].processToken = parser[tokenName].processToken || [];
|
|
12
|
+
(_a = parser[tokenName].processToken) === null || _a === void 0 ? void 0 : _a.push(process);
|
|
13
|
+
break;
|
|
14
|
+
}
|
|
15
|
+
case 'parserNodeAttrs': {
|
|
16
|
+
const { tokenName, process } = modifier;
|
|
17
|
+
parser[tokenName] = parser[tokenName] || {};
|
|
18
|
+
parser[tokenName].processNodeAttrs = parser[tokenName].processNodeAttrs || [];
|
|
19
|
+
(_b = parser[tokenName].processNodeAttrs) === null || _b === void 0 ? void 0 : _b.push(process);
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
case 'parserNode': {
|
|
23
|
+
const { nodeName, process } = modifier;
|
|
24
|
+
parser[nodeName] = parser[nodeName] || {};
|
|
25
|
+
parser[nodeName].processNode = parser[nodeName].processNode || [];
|
|
26
|
+
(_c = parser[nodeName].processNode) === null || _c === void 0 ? void 0 : _c.push(process);
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
case 'serializerNode': {
|
|
30
|
+
const { nodeName, process } = modifier;
|
|
31
|
+
serializer[nodeName] = serializer[nodeName] || {};
|
|
32
|
+
serializer[nodeName].processNode = serializer[nodeName].processNode || [];
|
|
33
|
+
(_d = serializer[nodeName].processNode) === null || _d === void 0 ? void 0 : _d.push(process);
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
case 'schemaNodeSpec': {
|
|
37
|
+
const { nodeName, allowedAttrs } = modifier;
|
|
38
|
+
schema[nodeName] = { allowedAttrs };
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
return { parser, schema, serializer };
|
|
44
|
+
}
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { AutocompletePopupProps } from '../../../utils/autocomplete-popup';
|
|
3
3
|
import type { CommandAction } from './types';
|
|
4
4
|
import './component.css';
|
|
5
|
-
export declare type CommandMenuItem = Pick<CommandAction, 'id' | 'title' | 'icon' | 'hotkey' | 'hint'>;
|
|
5
|
+
export declare type CommandMenuItem = Pick<CommandAction, 'id' | 'title' | 'icon' | 'hotkey' | 'hint' | 'preview'>;
|
|
6
6
|
export declare type CommandMenuComponentProps = AutocompletePopupProps & {
|
|
7
7
|
currentIndex?: number;
|
|
8
8
|
items: readonly CommandMenuItem[];
|
|
@@ -5,6 +5,7 @@ import { cn } from '../../../classname';
|
|
|
5
5
|
import { i18n } from '../../../i18n/suggest';
|
|
6
6
|
import { isFunction } from '../../../lodash';
|
|
7
7
|
import { ErrorLoggerBoundary } from '../../../react-utils/ErrorBoundary';
|
|
8
|
+
import { PreviewTooltip } from '../../../toolbar/PreviewTooltip';
|
|
8
9
|
import './component.css';
|
|
9
10
|
const b = cn('command-menu');
|
|
10
11
|
const placement = ['bottom-start', 'top-start', 'bottom-end', 'top-end'];
|
|
@@ -23,16 +24,17 @@ export const CommandMenuComponent = ({ anchor, currentIndex, items, onClick, onE
|
|
|
23
24
|
React.createElement("div", { className: b() },
|
|
24
25
|
React.createElement(List, { virtualized: true, items: items, sortable: false, filterable: false, emptyPlaceholder: i18n('empty-msg'), itemHeight: ITEM_HEIGHT, itemsHeight: calcListHeight(items.length), renderItem: renderItem, deactivateOnLeave: false, activeItemIndex: currentIndex, onItemClick: (_item, index) => onClick(index), className: b('list'), itemClassName: b('list-item') }))));
|
|
25
26
|
};
|
|
26
|
-
function renderItem({ id, title, icon, hotkey, hint }) {
|
|
27
|
+
function renderItem({ id, title, icon, hotkey, hint, preview }) {
|
|
27
28
|
const titleText = isFunction(title) ? title() : title;
|
|
28
29
|
const hintText = isFunction(hint) ? hint() : hint;
|
|
29
|
-
return (React.createElement(
|
|
30
|
-
React.createElement(
|
|
31
|
-
|
|
32
|
-
React.createElement("
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
return (React.createElement(PreviewTooltip, { preview: preview },
|
|
31
|
+
React.createElement("div", { key: id, className: b('item', { id }) },
|
|
32
|
+
React.createElement(Icon, { data: icon.data, size: 20, className: b('item-icon') }),
|
|
33
|
+
React.createElement("div", { className: b('item-body') },
|
|
34
|
+
React.createElement("span", { className: b('item-title') }, titleText),
|
|
35
|
+
React.createElement("div", { className: b('item-extra') },
|
|
36
|
+
hotkey && React.createElement(Hotkey, { value: hotkey, className: b('item-hotkey') }),
|
|
37
|
+
hintText && React.createElement(HelpPopover, { className: b('item-hint'), content: hintText }))))));
|
|
36
38
|
}
|
|
37
39
|
export function render(props) {
|
|
38
40
|
return (React.createElement(ErrorLoggerBoundary, null,
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{
|
|
2
|
+
"text": "This is a text without a title. \nBoth the title and the text \nbelow it can be highlighted in bold, italics, color, \nstrikethrough, and underline. You can also add lists, \ntables, links, formulas, anchors, \nand code blocks.",
|
|
3
|
+
"text-with-head": "This is the text with the title. \nBoth the title and the text \nbelow it can be highlighted in bold, italics, color, \nstrikethrough, and underline. You can also add lists, \ntables, links, formulas, anchors, \nand code blocks.",
|
|
4
|
+
"heading": "Text"
|
|
5
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const i18n: <G extends "text" | "heading" | "text-with-head", S extends string>(key: G | (string extends S ? S : never), params?: {
|
|
2
|
+
[key: string]: any;
|
|
3
|
+
} | undefined) => S extends G ? {
|
|
4
|
+
text: string;
|
|
5
|
+
"text-with-head": string;
|
|
6
|
+
heading: string;
|
|
7
|
+
}[G] : string;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{
|
|
2
|
+
"text": "Это текст без заголовка. И заголовок, и \nтекст под ним можно выделять \nполужирным, курсивом, цветом, \nзачёркивать и подчёркивать. А ещё — \nдобавлять списки, таблицы, ссылки, \nформулы, якоря и блоки кода",
|
|
3
|
+
"text-with-head": "Это текст с заголовком. И заголовок, и \nтекст под ним можно выделять \nполужирным, курсивом, цветом, \nзачёркивать и подчёркивать. А ещё — \nдобавлять списки, таблицы, ссылки, \nформулы, якоря и блоки кода.",
|
|
4
|
+
"heading": "О тексте"
|
|
5
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { icons } from '../../bundle/config/icons';
|
|
3
|
+
import { HeadingPreview } from '../../bundle/config/previews/HeadingPreview';
|
|
4
|
+
import { TextPreview } from '../../bundle/config/previews/TextPreview';
|
|
3
5
|
import { MToolbarColors } from '../../bundle/toolbar/markup/MToolbarColors';
|
|
4
6
|
import { MToolbarFilePopup } from '../../bundle/toolbar/markup/MToolbarFilePopup';
|
|
5
7
|
import { MToolbarImagePopup } from '../../bundle/toolbar/markup/MToolbarImagePopup';
|
|
@@ -453,6 +455,7 @@ export const heading1ItemView = {
|
|
|
453
455
|
title: i18n.bind(null, 'heading1'),
|
|
454
456
|
icon: icons.h1,
|
|
455
457
|
hotkey: f.toView(A.Heading1),
|
|
458
|
+
preview: React.createElement(HeadingPreview, { level: 1 }),
|
|
456
459
|
};
|
|
457
460
|
export const heading1ItemWysiwyg = {
|
|
458
461
|
exec: (e) => e.actions.toH1.run(),
|
|
@@ -470,6 +473,7 @@ export const heading2ItemView = {
|
|
|
470
473
|
title: i18n.bind(null, 'heading2'),
|
|
471
474
|
icon: icons.h2,
|
|
472
475
|
hotkey: f.toView(A.Heading2),
|
|
476
|
+
preview: React.createElement(HeadingPreview, { level: 2 }),
|
|
473
477
|
};
|
|
474
478
|
export const heading2ItemWysiwyg = {
|
|
475
479
|
exec: (e) => e.actions.toH2.run(),
|
|
@@ -487,6 +491,7 @@ export const heading3ItemView = {
|
|
|
487
491
|
title: i18n.bind(null, 'heading3'),
|
|
488
492
|
icon: icons.h3,
|
|
489
493
|
hotkey: f.toView(A.Heading3),
|
|
494
|
+
preview: React.createElement(HeadingPreview, { level: 3 }),
|
|
490
495
|
};
|
|
491
496
|
export const heading3ItemWysiwyg = {
|
|
492
497
|
exec: (e) => e.actions.toH3.run(),
|
|
@@ -504,6 +509,7 @@ export const heading4ItemView = {
|
|
|
504
509
|
title: i18n.bind(null, 'heading4'),
|
|
505
510
|
icon: icons.h4,
|
|
506
511
|
hotkey: f.toView(A.Heading4),
|
|
512
|
+
preview: React.createElement(HeadingPreview, { level: 4 }),
|
|
507
513
|
};
|
|
508
514
|
export const heading4ItemWysiwyg = {
|
|
509
515
|
exec: (e) => e.actions.toH4.run(),
|
|
@@ -521,6 +527,7 @@ export const heading5ItemView = {
|
|
|
521
527
|
title: i18n.bind(null, 'heading5'),
|
|
522
528
|
icon: icons.h5,
|
|
523
529
|
hotkey: f.toView(A.Heading5),
|
|
530
|
+
preview: React.createElement(HeadingPreview, { level: 5 }),
|
|
524
531
|
};
|
|
525
532
|
export const heading5ItemWysiwyg = {
|
|
526
533
|
exec: (e) => e.actions.toH5.run(),
|
|
@@ -538,6 +545,7 @@ export const heading6ItemView = {
|
|
|
538
545
|
title: i18n.bind(null, 'heading6'),
|
|
539
546
|
icon: icons.h6,
|
|
540
547
|
hotkey: f.toView(A.Heading6),
|
|
548
|
+
preview: React.createElement(HeadingPreview, { level: 6 }),
|
|
541
549
|
};
|
|
542
550
|
export const heading6ItemWysiwyg = {
|
|
543
551
|
exec: (e) => e.actions.toH6.run(),
|
|
@@ -653,6 +661,7 @@ export const paragraphItemView = {
|
|
|
653
661
|
icon: icons.text,
|
|
654
662
|
hotkey: f.toView(A.Text),
|
|
655
663
|
doNotActivateList: true,
|
|
664
|
+
preview: React.createElement(TextPreview, null),
|
|
656
665
|
};
|
|
657
666
|
export const paragraphItemWisywig = {
|
|
658
667
|
exec: (e) => e.actions.toParagraph.run(),
|
|
@@ -22,6 +22,7 @@ export declare type ToolbarItemView<T extends ToolbarDataType = ToolbarDataType.
|
|
|
22
22
|
} & (T extends ToolbarDataType.SingleButton ? {
|
|
23
23
|
icon: ToolbarIconData;
|
|
24
24
|
title: string | (() => string);
|
|
25
|
+
preview?: React.ReactNode;
|
|
25
26
|
} : T extends ToolbarDataType.ListButton ? {
|
|
26
27
|
withArrow?: boolean;
|
|
27
28
|
icon: ToolbarIconData;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Tooltip } from '@gravity-ui/uikit';
|
|
3
|
+
import { cn } from '../classname';
|
|
4
|
+
import { ToolbarTooltipDelay } from './const';
|
|
5
|
+
import './PreviewTooltip.css';
|
|
6
|
+
const b = cn('preview-tooltip');
|
|
7
|
+
export const PreviewTooltip = ({ preview, children }) => {
|
|
8
|
+
return (React.createElement(Tooltip, { placement: "right", className: b(), contentClassName: b('content'), disabled: !preview, openDelay: ToolbarTooltipDelay.Open, closeDelay: ToolbarTooltipDelay.Close, content: preview }, children));
|
|
9
|
+
};
|
|
@@ -6,6 +6,7 @@ import { cn } from '../classname';
|
|
|
6
6
|
import { i18n } from '../i18n/common';
|
|
7
7
|
import { isFunction } from '../lodash';
|
|
8
8
|
import { useBooleanState } from '../react-utils/hooks';
|
|
9
|
+
import { PreviewTooltip } from './PreviewTooltip';
|
|
9
10
|
import { ToolbarTooltipDelay } from './const';
|
|
10
11
|
import './ToolbarListButton.css';
|
|
11
12
|
const b = cn('toolbar-list-button');
|
|
@@ -46,7 +47,7 @@ export function ToolbarListButton({ className, editor, focus, onClick, icon, tit
|
|
|
46
47
|
React.createElement(Menu, { size: "l", className: b('menu') }, data
|
|
47
48
|
.map((data) => {
|
|
48
49
|
var _a;
|
|
49
|
-
const { id, title, icon, hotkey, isActive, isEnable, exec, hint, hintWhenDisabled, disabledPopoverVisible = true, } = data;
|
|
50
|
+
const { id, title, icon, hotkey, isActive, isEnable, exec, hint, hintWhenDisabled, disabledPopoverVisible = true, preview, } = data;
|
|
50
51
|
const titleText = isFunction(title) ? title() : title;
|
|
51
52
|
const hintText = isFunction(hint) ? hint() : hint;
|
|
52
53
|
const disabled = !isEnable(editor);
|
|
@@ -56,24 +57,28 @@ export function ToolbarListButton({ className, editor, focus, onClick, icon, tit
|
|
|
56
57
|
: typeof hintWhenDisabled === 'function'
|
|
57
58
|
? hintWhenDisabled()
|
|
58
59
|
: i18n('toolbar_action_disabled');
|
|
60
|
+
const handleClick = () => {
|
|
61
|
+
hide();
|
|
62
|
+
if (isPopupItem(data)) {
|
|
63
|
+
setPopupItem(data);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
setPopupItem(undefined);
|
|
67
|
+
focus();
|
|
68
|
+
exec(editor);
|
|
69
|
+
onClick === null || onClick === void 0 ? void 0 : onClick(id);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
59
72
|
return (React.createElement(Popover, { className: b('action-disabled-popover'), tooltipContentClassName: b('action-disabled-tooltip'), content: hintWhenDisabledText, placement: 'left', disabled: hideHintWhenDisabled, key: id },
|
|
60
|
-
React.createElement(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
onClick === null || onClick === void 0 ? void 0 : onClick(id);
|
|
70
|
-
}
|
|
71
|
-
}, icon: React.createElement(Icon, { data: icon.data, size: (_a = icon.size) !== null && _a !== void 0 ? _a : 16 }), extraProps: { 'aria-label': titleText } },
|
|
72
|
-
React.createElement("div", { className: b('item') },
|
|
73
|
-
titleText,
|
|
74
|
-
React.createElement("div", { className: b('extra') },
|
|
75
|
-
hotkey && React.createElement(Hotkey, { value: hotkey }),
|
|
76
|
-
hintText && (React.createElement(HelpPopover, { className: b('hint'), content: hintText })))))));
|
|
73
|
+
React.createElement(PreviewTooltip, { preview: preview },
|
|
74
|
+
React.createElement(Menu.Item, { key: id, active: isActive(editor), disabled: !isEnable(editor), onClick: handleClick, icon: React.createElement(Icon, { data: icon.data, size: (_a = icon.size) !== null && _a !== void 0 ? _a : 16 }), extraProps: {
|
|
75
|
+
'aria-label': titleText,
|
|
76
|
+
} },
|
|
77
|
+
React.createElement("div", { className: b('item') },
|
|
78
|
+
titleText,
|
|
79
|
+
React.createElement("div", { className: b('extra') },
|
|
80
|
+
hotkey && React.createElement(Hotkey, { value: hotkey }),
|
|
81
|
+
hintText && (React.createElement(HelpPopover, { className: b('hint'), content: hintText }))))))));
|
|
77
82
|
})
|
|
78
83
|
.filter(Boolean))),
|
|
79
84
|
popupItem
|
|
@@ -17,6 +17,7 @@ export declare type ToolbarItemData<E> = {
|
|
|
17
17
|
title: string | (() => string);
|
|
18
18
|
hint?: string | (() => string);
|
|
19
19
|
hotkey?: HotkeyProps['value'];
|
|
20
|
+
preview?: React.ReactNode;
|
|
20
21
|
/** @deprecated Use _hintWhenDisabled_ setting instead */
|
|
21
22
|
disabledPopoverVisible?: boolean;
|
|
22
23
|
/**
|
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 '14.
|
|
2
|
+
export const VERSION = typeof '14.12.0' !== 'undefined' ? '14.12.0' : 'unknown';
|
package/build/styles.css
CHANGED
|
@@ -345,6 +345,14 @@
|
|
|
345
345
|
display: flex;
|
|
346
346
|
gap: 0 8px;
|
|
347
347
|
}
|
|
348
|
+
.g-md-preview-tooltip {
|
|
349
|
+
padding: var(--g-spacing-3);
|
|
350
|
+
border-radius: var(--g-border-radius-s);
|
|
351
|
+
background-color: var(--g-color-base-float-heavy);
|
|
352
|
+
}
|
|
353
|
+
.g-md-preview-tooltip .g-popup__content:first-child {
|
|
354
|
+
padding: 0 0 0 var(--g-spacing-2);
|
|
355
|
+
}
|
|
348
356
|
.g-md-toolbar {
|
|
349
357
|
display: flex;
|
|
350
358
|
}
|
|
@@ -583,6 +591,51 @@
|
|
|
583
591
|
.g-md-base-tooltip__content__switch {
|
|
584
592
|
margin-right: 28px;
|
|
585
593
|
}
|
|
594
|
+
:root {
|
|
595
|
+
--toolbar-item-preview-width: 144px;
|
|
596
|
+
--toolbar-item-preview-height: 104px;
|
|
597
|
+
--toolbar-item-preview-h1-margin: 10px 0 2px;
|
|
598
|
+
--toolbar-item-preview-h2-margin: 20px 0 4px;
|
|
599
|
+
--toolbar-item-preview-h3-margin: 24px 0 4px;
|
|
600
|
+
--toolbar-item-preview-h4-margin: 24px 0 4px;
|
|
601
|
+
--toolbar-item-preview-h5-margin: 26px 0 6px;
|
|
602
|
+
--toolbar-item-preview-h6-margin: 28px 0 6px;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
.g-md-action-preview {
|
|
606
|
+
overflow: hidden;
|
|
607
|
+
width: var(--toolbar-item-preview-width);
|
|
608
|
+
height: var(--toolbar-item-preview-height);
|
|
609
|
+
white-space: pre;
|
|
610
|
+
}
|
|
611
|
+
.g-md-action-preview.yfm > *:not(h2):not(h3):not(h4):not(h5):not(h6):first-child {
|
|
612
|
+
/* stylelint-disable-next-line declaration-no-important */
|
|
613
|
+
margin: var(--toolbar-item-preview-h1-margin) !important;
|
|
614
|
+
}
|
|
615
|
+
.g-md-action-preview.yfm > h2 {
|
|
616
|
+
/* stylelint-disable-next-line declaration-no-important */
|
|
617
|
+
margin: var(--toolbar-item-preview-h2-margin) !important;
|
|
618
|
+
}
|
|
619
|
+
.g-md-action-preview.yfm > h3 {
|
|
620
|
+
/* stylelint-disable-next-line declaration-no-important */
|
|
621
|
+
margin: var(--toolbar-item-preview-h3-margin) !important;
|
|
622
|
+
}
|
|
623
|
+
.g-md-action-preview.yfm > h4 {
|
|
624
|
+
/* stylelint-disable-next-line declaration-no-important */
|
|
625
|
+
margin: var(--toolbar-item-preview-h4-margin) !important;
|
|
626
|
+
}
|
|
627
|
+
.g-md-action-preview.yfm > h5 {
|
|
628
|
+
/* stylelint-disable-next-line declaration-no-important */
|
|
629
|
+
margin: var(--toolbar-item-preview-h5-margin) !important;
|
|
630
|
+
}
|
|
631
|
+
.g-md-action-preview.yfm > h6 {
|
|
632
|
+
/* stylelint-disable-next-line declaration-no-important */
|
|
633
|
+
margin: var(--toolbar-item-preview-h6-margin) !important;
|
|
634
|
+
}
|
|
635
|
+
.g-md-action-preview__text-with-head {
|
|
636
|
+
margin-top: 0;
|
|
637
|
+
color: var(--g-color-text-hint);
|
|
638
|
+
}
|
|
586
639
|
.g-md-markdown-hints {
|
|
587
640
|
min-width: 210px;
|
|
588
641
|
line-height: var(--g-text-code-1-line-height);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gravity-ui/markdown-editor",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.12.0",
|
|
4
4
|
"description": "Markdown wysiwyg and markup editor",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -199,10 +199,11 @@
|
|
|
199
199
|
"react-error-boundary": "^3.1.4",
|
|
200
200
|
"react-hotkeys-hook": "4.5.0",
|
|
201
201
|
"react-use": "^17.3.2",
|
|
202
|
-
"tslib": "^2.3.1"
|
|
202
|
+
"tslib": "^2.3.1",
|
|
203
|
+
"uuid": "11.0.5"
|
|
203
204
|
},
|
|
204
205
|
"devDependencies": {
|
|
205
|
-
"@diplodoc/cut-extension": "^0.
|
|
206
|
+
"@diplodoc/cut-extension": "^0.6.1",
|
|
206
207
|
"@diplodoc/folding-headings-extension": "0.1.0",
|
|
207
208
|
"@diplodoc/html-extension": "^2.5.0",
|
|
208
209
|
"@diplodoc/latex-extension": "1.0.3",
|
|
@@ -288,7 +289,7 @@
|
|
|
288
289
|
}
|
|
289
290
|
},
|
|
290
291
|
"peerDependencies": {
|
|
291
|
-
"@diplodoc/cut-extension": "^0.3.1 || ^0.4.0 || ^0.5.0",
|
|
292
|
+
"@diplodoc/cut-extension": "^0.3.1 || ^0.4.0 || ^0.5.0 || ^0.6.1 || ^0.7.1",
|
|
292
293
|
"@diplodoc/folding-headings-extension": "^0.1.0",
|
|
293
294
|
"@diplodoc/html-extension": "^2.3.2",
|
|
294
295
|
"@diplodoc/latex-extension": "^1.0.3",
|