@gravity-ui/markdown-editor 14.8.0 → 14.10.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/README.md +16 -14
- package/build/cjs/bundle/Editor.d.ts +2 -0
- package/build/cjs/bundle/Editor.js +15 -4
- package/build/cjs/bundle/MarkdownEditorView.d.ts +27 -0
- package/build/cjs/bundle/MarkdownEditorView.js +19 -2
- package/build/cjs/bundle/config/action-names.d.ts +1 -1
- package/build/cjs/bundle/config/action-names.js +51 -27
- package/build/cjs/bundle/config/index.d.ts +3 -0
- package/build/cjs/bundle/config/index.js +3 -0
- package/build/cjs/bundle/config/markup.js +3 -0
- package/build/cjs/bundle/config/wysiwyg.d.ts +3 -0
- package/build/cjs/bundle/toolbar/utils/flattenPreset.d.ts +2 -0
- package/build/cjs/bundle/toolbar/utils/flattenPreset.js +14 -0
- package/build/cjs/bundle/toolbar/utils/toolbarsConfigs.d.ts +17 -0
- package/build/cjs/bundle/toolbar/utils/toolbarsConfigs.js +60 -0
- package/build/cjs/bundle/types.d.ts +6 -0
- package/build/cjs/bundle/useMarkdownEditor.js +8 -2
- package/build/cjs/bundle/wysiwyg-preset.d.ts +1 -0
- package/build/cjs/bundle/wysiwyg-preset.js +1 -1
- package/build/cjs/core/Editor.d.ts +3 -1
- package/build/cjs/core/Editor.js +2 -1
- package/build/cjs/core/ExtensionsManager.d.ts +2 -0
- package/build/cjs/core/ExtensionsManager.js +8 -4
- package/build/cjs/core/ParserTokensRegistry.d.ts +2 -1
- package/build/cjs/core/ParserTokensRegistry.js +2 -2
- package/build/cjs/core/markdown/MarkdownParser.d.ts +3 -1
- package/build/cjs/core/markdown/MarkdownParser.js +5 -2
- package/build/cjs/core/markdown/MarkdownSerializer.js +1 -1
- package/build/cjs/core/markdown/ProseMirrorTransformer/emptyRowTransformer.d.ts +2 -0
- package/build/cjs/core/markdown/ProseMirrorTransformer/emptyRowTransformer.js +15 -0
- package/build/cjs/core/markdown/ProseMirrorTransformer/getTransformers.d.ts +7 -0
- package/build/cjs/core/markdown/ProseMirrorTransformer/getTransformers.js +13 -0
- package/build/cjs/core/markdown/ProseMirrorTransformer/index.d.ts +15 -0
- package/build/cjs/core/markdown/ProseMirrorTransformer/index.js +25 -0
- package/build/cjs/extensions/additional/Math/MathSpecs/index.js +1 -0
- package/build/cjs/extensions/base/BaseSchema/BaseSchemaSpecs/index.d.ts +1 -0
- package/build/cjs/extensions/base/BaseSchema/BaseSchemaSpecs/index.js +23 -3
- package/build/cjs/extensions/behavior/Selection/selection.js +1 -5
- package/build/cjs/extensions/markdown/Blockquote/BlockquoteSpecs/index.js +1 -0
- package/build/cjs/extensions/markdown/CodeBlock/commands.js +1 -1
- package/build/cjs/extensions/markdown/HorizontalRule/HorizontalRuleSpecs/index.js +1 -0
- package/build/cjs/extensions/markdown/Link/paste-plugin.js +21 -5
- package/build/cjs/extensions/yfm/YfmTabs/YfmTabsSpecs/schema.js +1 -0
- package/build/cjs/i18n/empty-row/en.json +3 -0
- package/build/cjs/i18n/empty-row/index.d.ts +5 -0
- package/build/cjs/i18n/empty-row/index.js +9 -0
- package/build/cjs/i18n/empty-row/ru.json +3 -0
- package/build/cjs/i18n/menubar/en.json +1 -0
- package/build/cjs/i18n/menubar/index.d.ts +2 -1
- package/build/cjs/i18n/menubar/ru.json +1 -0
- package/build/cjs/i18n/yfm-note/index.d.ts +1 -1
- package/build/cjs/index.d.ts +1 -0
- package/build/cjs/index.js +1 -0
- package/build/cjs/markup/codemirror/autocomplete/emptyRow.d.ts +9 -0
- package/build/cjs/markup/codemirror/autocomplete/emptyRow.js +26 -0
- package/build/cjs/markup/codemirror/autocomplete/index.d.ts +5 -0
- package/build/cjs/markup/codemirror/autocomplete/index.js +14 -0
- package/build/cjs/markup/codemirror/create.d.ts +1 -0
- package/build/cjs/markup/codemirror/create.js +30 -12
- package/build/cjs/markup/codemirror/smart-reindent/index.d.ts +4 -0
- package/build/cjs/markup/codemirror/smart-reindent/index.js +42 -0
- package/build/cjs/markup/codemirror/smart-reindent/utils.d.ts +15 -0
- package/build/cjs/markup/codemirror/smart-reindent/utils.js +59 -0
- package/build/cjs/markup/codemirror/yfm.d.ts +2 -1
- package/build/cjs/markup/codemirror/yfm.js +3 -3
- package/build/cjs/markup/commands/emptyRow.d.ts +2 -0
- package/build/cjs/markup/commands/emptyRow.js +43 -0
- package/build/cjs/markup/commands/index.d.ts +1 -0
- package/build/cjs/markup/commands/index.js +1 -0
- package/build/cjs/modules/toolbars/constants.d.ts +13 -0
- package/build/cjs/modules/toolbars/constants.js +18 -0
- package/build/cjs/modules/toolbars/items.d.ts +127 -0
- package/build/cjs/modules/toolbars/items.js +736 -0
- package/build/cjs/modules/toolbars/presets.d.ts +6 -0
- package/build/cjs/modules/toolbars/presets.js +465 -0
- package/build/cjs/modules/toolbars/types.d.ts +62 -0
- package/build/cjs/modules/toolbars/types.js +2 -0
- package/build/cjs/shortcuts/const.d.ts +1 -0
- package/build/cjs/shortcuts/const.js +1 -0
- package/build/cjs/shortcuts/default.js +1 -0
- package/build/cjs/toolbar/types.d.ts +8 -0
- package/build/cjs/toolbar/types.js +2 -0
- package/build/cjs/version.js +1 -1
- package/build/esm/bundle/Editor.d.ts +2 -0
- package/build/esm/bundle/Editor.js +15 -4
- package/build/esm/bundle/MarkdownEditorView.d.ts +27 -0
- package/build/esm/bundle/MarkdownEditorView.js +19 -2
- package/build/esm/bundle/config/action-names.d.ts +1 -1
- package/build/esm/bundle/config/action-names.js +51 -27
- package/build/esm/bundle/config/index.d.ts +3 -0
- package/build/esm/bundle/config/index.js +3 -0
- package/build/esm/bundle/config/markup.js +3 -0
- package/build/esm/bundle/config/wysiwyg.d.ts +3 -0
- package/build/esm/bundle/toolbar/utils/flattenPreset.d.ts +2 -0
- package/build/esm/bundle/toolbar/utils/flattenPreset.js +10 -0
- package/build/esm/bundle/toolbar/utils/toolbarsConfigs.d.ts +17 -0
- package/build/esm/bundle/toolbar/utils/toolbarsConfigs.js +55 -0
- package/build/esm/bundle/types.d.ts +6 -0
- package/build/esm/bundle/useMarkdownEditor.js +8 -2
- package/build/esm/bundle/wysiwyg-preset.d.ts +1 -0
- package/build/esm/bundle/wysiwyg-preset.js +1 -1
- package/build/esm/core/Editor.d.ts +3 -1
- package/build/esm/core/Editor.js +2 -1
- package/build/esm/core/ExtensionsManager.d.ts +2 -0
- package/build/esm/core/ExtensionsManager.js +8 -4
- package/build/esm/core/ParserTokensRegistry.d.ts +2 -1
- package/build/esm/core/ParserTokensRegistry.js +2 -2
- package/build/esm/core/markdown/MarkdownParser.d.ts +3 -1
- package/build/esm/core/markdown/MarkdownParser.js +5 -2
- package/build/esm/core/markdown/MarkdownSerializer.js +1 -1
- package/build/esm/core/markdown/ProseMirrorTransformer/emptyRowTransformer.d.ts +2 -0
- package/build/esm/core/markdown/ProseMirrorTransformer/emptyRowTransformer.js +11 -0
- package/build/esm/core/markdown/ProseMirrorTransformer/getTransformers.d.ts +7 -0
- package/build/esm/core/markdown/ProseMirrorTransformer/getTransformers.js +9 -0
- package/build/esm/core/markdown/ProseMirrorTransformer/index.d.ts +15 -0
- package/build/esm/core/markdown/ProseMirrorTransformer/index.js +21 -0
- package/build/esm/extensions/additional/Math/MathSpecs/index.js +1 -0
- package/build/esm/extensions/base/BaseSchema/BaseSchemaSpecs/index.d.ts +1 -0
- package/build/esm/extensions/base/BaseSchema/BaseSchemaSpecs/index.js +23 -3
- package/build/esm/extensions/behavior/Selection/selection.js +1 -5
- package/build/esm/extensions/markdown/Blockquote/BlockquoteSpecs/index.js +1 -0
- package/build/esm/extensions/markdown/CodeBlock/commands.js +1 -1
- package/build/esm/extensions/markdown/HorizontalRule/HorizontalRuleSpecs/index.js +1 -0
- package/build/esm/extensions/markdown/Link/paste-plugin.js +21 -5
- package/build/esm/extensions/yfm/YfmTabs/YfmTabsSpecs/schema.js +1 -0
- package/build/esm/i18n/empty-row/en.json +3 -0
- package/build/esm/i18n/empty-row/index.d.ts +5 -0
- package/build/esm/i18n/empty-row/index.js +5 -0
- package/build/esm/i18n/empty-row/ru.json +3 -0
- package/build/esm/i18n/menubar/en.json +1 -0
- package/build/esm/i18n/menubar/index.d.ts +2 -1
- package/build/esm/i18n/menubar/ru.json +1 -0
- package/build/esm/i18n/yfm-note/index.d.ts +1 -1
- package/build/esm/index.d.ts +1 -0
- package/build/esm/index.js +1 -0
- package/build/esm/markup/codemirror/autocomplete/emptyRow.d.ts +9 -0
- package/build/esm/markup/codemirror/autocomplete/emptyRow.js +23 -0
- package/build/esm/markup/codemirror/autocomplete/index.d.ts +5 -0
- package/build/esm/markup/codemirror/autocomplete/index.js +10 -0
- package/build/esm/markup/codemirror/create.d.ts +1 -0
- package/build/esm/markup/codemirror/create.js +31 -13
- package/build/esm/markup/codemirror/smart-reindent/index.d.ts +4 -0
- package/build/esm/markup/codemirror/smart-reindent/index.js +38 -0
- package/build/esm/markup/codemirror/smart-reindent/utils.d.ts +15 -0
- package/build/esm/markup/codemirror/smart-reindent/utils.js +55 -0
- package/build/esm/markup/codemirror/yfm.d.ts +2 -1
- package/build/esm/markup/codemirror/yfm.js +1 -1
- package/build/esm/markup/commands/emptyRow.d.ts +2 -0
- package/build/esm/markup/commands/emptyRow.js +39 -0
- package/build/esm/markup/commands/index.d.ts +1 -0
- package/build/esm/markup/commands/index.js +1 -0
- package/build/esm/modules/toolbars/constants.d.ts +13 -0
- package/build/esm/modules/toolbars/constants.js +15 -0
- package/build/esm/modules/toolbars/items.d.ts +127 -0
- package/build/esm/modules/toolbars/items.js +730 -0
- package/build/esm/modules/toolbars/presets.d.ts +6 -0
- package/build/esm/modules/toolbars/presets.js +462 -0
- package/build/esm/modules/toolbars/types.d.ts +62 -0
- package/build/esm/modules/toolbars/types.js +1 -0
- package/build/esm/shortcuts/const.d.ts +1 -0
- package/build/esm/shortcuts/const.js +1 -0
- package/build/esm/shortcuts/default.js +1 -0
- package/build/esm/toolbar/types.d.ts +8 -0
- package/build/esm/toolbar/types.js +2 -0
- package/build/esm/version.js +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Mark } from 'prosemirror-model';
|
|
2
2
|
import { logger } from '../../logger';
|
|
3
|
+
import { ProseMirrorTransformer } from './ProseMirrorTransformer';
|
|
3
4
|
const openSuffix = '_open';
|
|
4
5
|
const closeSuffix = '_close';
|
|
5
6
|
var TokenType;
|
|
@@ -9,12 +10,13 @@ var TokenType;
|
|
|
9
10
|
TokenType["default"] = "default";
|
|
10
11
|
})(TokenType || (TokenType = {}));
|
|
11
12
|
export class MarkdownParser {
|
|
12
|
-
constructor(schema, tokenizer, tokens) {
|
|
13
|
+
constructor(schema, tokenizer, tokens, pmTransformers) {
|
|
13
14
|
this.stack = [];
|
|
14
15
|
this.schema = schema;
|
|
15
16
|
this.marks = Mark.none;
|
|
16
17
|
this.tokens = tokens;
|
|
17
18
|
this.tokenizer = tokenizer;
|
|
19
|
+
this.pmTransformers = pmTransformers;
|
|
18
20
|
}
|
|
19
21
|
validateLink(url) {
|
|
20
22
|
return this.tokenizer.validateLink(url);
|
|
@@ -47,7 +49,8 @@ export class MarkdownParser {
|
|
|
47
49
|
do {
|
|
48
50
|
doc = this.closeNode();
|
|
49
51
|
} while (this.stack.length);
|
|
50
|
-
|
|
52
|
+
const pmTransformer = new ProseMirrorTransformer(this.pmTransformers);
|
|
53
|
+
return doc ? pmTransformer.transform(doc) : this.schema.topNodeType.createAndFill();
|
|
51
54
|
}
|
|
52
55
|
finally {
|
|
53
56
|
logger.metrics({ component: 'parser', event: 'parse', duration: Date.now() - time });
|
|
@@ -161,7 +161,7 @@ export class MarkdownSerializerState {
|
|
|
161
161
|
const startOfLine = this.atBlank() || this.closed;
|
|
162
162
|
this.write();
|
|
163
163
|
let text = lines[i];
|
|
164
|
-
if (escape !== false)
|
|
164
|
+
if (escape !== false && this.options.escape !== false)
|
|
165
165
|
text = this.esc(text, startOfLine);
|
|
166
166
|
if (this.escapeWhitespace)
|
|
167
167
|
text = this.escWhitespace(text);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const transformEmptyParagraph = (node) => {
|
|
2
|
+
var _a, _b;
|
|
3
|
+
if (node.type !== 'paragraph')
|
|
4
|
+
return;
|
|
5
|
+
if (((_a = node.content) === null || _a === void 0 ? void 0 : _a.length) !== 1)
|
|
6
|
+
return;
|
|
7
|
+
if (((_b = node.content[0]) === null || _b === void 0 ? void 0 : _b.type) !== 'text')
|
|
8
|
+
return;
|
|
9
|
+
if (node.content[0].text === String.fromCharCode(160))
|
|
10
|
+
delete node.content;
|
|
11
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { TransformFn } from '.';
|
|
2
|
+
declare type GetTransformersProps = {
|
|
3
|
+
emptyRowTransformer?: boolean;
|
|
4
|
+
};
|
|
5
|
+
declare type GetPMTransformersType = (config: GetTransformersProps) => TransformFn[];
|
|
6
|
+
export declare const getPMTransformers: GetPMTransformersType;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// TODO: add a new method to the ExtensionBuilder
|
|
2
|
+
import { transformEmptyParagraph } from './emptyRowTransformer';
|
|
3
|
+
export const getPMTransformers = ({ emptyRowTransformer }) => {
|
|
4
|
+
const transformers = [];
|
|
5
|
+
if (emptyRowTransformer) {
|
|
6
|
+
transformers.push(transformEmptyParagraph);
|
|
7
|
+
}
|
|
8
|
+
return transformers;
|
|
9
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Node } from 'prosemirror-model';
|
|
2
|
+
declare type PMNodeJSON = {
|
|
3
|
+
type: string;
|
|
4
|
+
attrs?: Record<string, any>;
|
|
5
|
+
content?: PMNodeJSON[];
|
|
6
|
+
text?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare type TransformFn = (node: PMNodeJSON) => void;
|
|
9
|
+
export declare class ProseMirrorTransformer {
|
|
10
|
+
private readonly _transformers;
|
|
11
|
+
constructor(fns: TransformFn[]);
|
|
12
|
+
transform(doc: Node): Node;
|
|
13
|
+
transformJSON(node: PMNodeJSON): void;
|
|
14
|
+
}
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Node } from 'prosemirror-model';
|
|
2
|
+
export class ProseMirrorTransformer {
|
|
3
|
+
constructor(fns) {
|
|
4
|
+
this._transformers = fns;
|
|
5
|
+
}
|
|
6
|
+
transform(doc) {
|
|
7
|
+
const docJSON = doc.toJSON();
|
|
8
|
+
this.transformJSON(docJSON);
|
|
9
|
+
return Node.fromJSON(doc.type.schema, docJSON);
|
|
10
|
+
}
|
|
11
|
+
transformJSON(node) {
|
|
12
|
+
for (const fn of this._transformers) {
|
|
13
|
+
fn(node);
|
|
14
|
+
}
|
|
15
|
+
if (node.content) {
|
|
16
|
+
for (const child of node.content) {
|
|
17
|
+
this.transformJSON(child);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -8,5 +8,6 @@ export declare enum BaseNode {
|
|
|
8
8
|
export declare const pType: (schema: import("prosemirror-model").Schema<any, any>) => import("prosemirror-model").NodeType;
|
|
9
9
|
export declare type BaseSchemaSpecsOptions = {
|
|
10
10
|
paragraphPlaceholder?: NonNullable<NodeSpec['placeholder']>['content'];
|
|
11
|
+
preserveEmptyRows?: boolean;
|
|
11
12
|
};
|
|
12
13
|
export declare const BaseSchemaSpecs: ExtensionAuto<BaseSchemaSpecsOptions>;
|
|
@@ -42,6 +42,7 @@ export const BaseSchemaSpecs = (builder, opts) => {
|
|
|
42
42
|
0,
|
|
43
43
|
];
|
|
44
44
|
},
|
|
45
|
+
selectable: true,
|
|
45
46
|
placeholder: opts.paragraphPlaceholder
|
|
46
47
|
? {
|
|
47
48
|
content: opts.paragraphPlaceholder,
|
|
@@ -50,9 +51,28 @@ export const BaseSchemaSpecs = (builder, opts) => {
|
|
|
50
51
|
: undefined,
|
|
51
52
|
},
|
|
52
53
|
fromMd: { tokenSpec: { name: BaseNode.Paragraph, type: 'block' } },
|
|
53
|
-
toMd: (state, node) => {
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
toMd: (state, node, parent) => {
|
|
55
|
+
/*
|
|
56
|
+
An empty line is added only if there is some content in the parent element.
|
|
57
|
+
This is necessary in order to prevent an empty document with empty lines
|
|
58
|
+
*/
|
|
59
|
+
if (opts.preserveEmptyRows && !node.content.size) {
|
|
60
|
+
let isParentEmpty = true;
|
|
61
|
+
for (let index = 0; index < parent.content.childCount; index++) {
|
|
62
|
+
const parentChild = parent.content.child(index);
|
|
63
|
+
if (parentChild.content.size !== 0 ||
|
|
64
|
+
parentChild.type.name !== 'paragraph') {
|
|
65
|
+
isParentEmpty = false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (!isParentEmpty) {
|
|
69
|
+
state.write(' \n\n');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
state.renderInline(node);
|
|
74
|
+
state.closeBlock(node);
|
|
75
|
+
}
|
|
56
76
|
},
|
|
57
77
|
}));
|
|
58
78
|
};
|
|
@@ -71,11 +71,7 @@ const getTopLevelNodesFromSelection = (selection, doc) => {
|
|
|
71
71
|
const { from, to } = selection;
|
|
72
72
|
doc.nodesBetween(from, to, (node, pos) => {
|
|
73
73
|
const withinSelection = from <= pos && pos + node.nodeSize <= to;
|
|
74
|
-
if (node &&
|
|
75
|
-
node.type.name !== 'paragraph' &&
|
|
76
|
-
!node.isText &&
|
|
77
|
-
node.type.spec.selectable &&
|
|
78
|
-
withinSelection) {
|
|
74
|
+
if (node && !node.isText && node.type.spec.selectable !== false && withinSelection) {
|
|
79
75
|
nodes.push({ node, pos });
|
|
80
76
|
return false;
|
|
81
77
|
}
|
|
@@ -16,7 +16,7 @@ export const setCodeBlockType = ({ serializer }) => (state, dispatch) => {
|
|
|
16
16
|
if (!setBlockType(nodeType)(state))
|
|
17
17
|
return false;
|
|
18
18
|
if (dispatch) {
|
|
19
|
-
const markup = serializer.serialize(state.selection.content().content);
|
|
19
|
+
const markup = serializer.serialize(state.selection.content().content, { escape: false });
|
|
20
20
|
dispatch(state.tr.replaceSelectionWith(nodeType.createAndFill({}, markup ? state.schema.text(markup) : null)));
|
|
21
21
|
}
|
|
22
22
|
return true;
|
|
@@ -10,21 +10,37 @@ export function linkPasteEnhance({ markupParser: parser }) {
|
|
|
10
10
|
paste(view, e) {
|
|
11
11
|
const { state, dispatch } = view;
|
|
12
12
|
const sel = state.selection;
|
|
13
|
+
let tr = null;
|
|
13
14
|
if (isTextSelection(sel) ||
|
|
14
15
|
(isNodeSelection(sel) && sel.node.type === imageType(state.schema))) {
|
|
15
16
|
const { $from, $to } = sel;
|
|
16
|
-
if ($from.pos
|
|
17
|
+
if ($from.pos === $to.pos) {
|
|
17
18
|
const url = getUrl(e.clipboardData, parser);
|
|
18
19
|
if (url) {
|
|
19
|
-
const
|
|
20
|
+
const linkMarkType = linkType(state.schema);
|
|
21
|
+
tr = state.tr.replaceSelectionWith(state.schema.text(url, [
|
|
22
|
+
...$from
|
|
23
|
+
.marks()
|
|
24
|
+
.filter((mark) => mark.type !== linkMarkType),
|
|
25
|
+
linkMarkType.create({ [LinkAttr.Href]: url }),
|
|
26
|
+
]), false);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
else if ($from.sameParent($to)) {
|
|
30
|
+
const url = getUrl(e.clipboardData, parser);
|
|
31
|
+
if (url) {
|
|
32
|
+
tr = state.tr.addMark($from.pos, $to.pos, linkType(state.schema).create({
|
|
20
33
|
[LinkAttr.Href]: url,
|
|
21
34
|
}));
|
|
22
|
-
|
|
23
|
-
e.preventDefault();
|
|
24
|
-
return true;
|
|
35
|
+
tr.setSelection(TextSelection.create(tr.doc, $to.pos));
|
|
25
36
|
}
|
|
26
37
|
}
|
|
27
38
|
}
|
|
39
|
+
if (tr) {
|
|
40
|
+
dispatch(tr.scrollIntoView());
|
|
41
|
+
e.preventDefault();
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
28
44
|
return false;
|
|
29
45
|
},
|
|
30
46
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const i18n: <G extends "bold" | "code" | "colorify" | "mono" | "link" | "italic" | "strike" | "underline" | "mark" | "quote" | "text" | "html" | "cut" | "table" | "image" | "code_inline" | "list" | "heading" | "note" | "file" | "checkbox" | "emoji" | "
|
|
1
|
+
export declare const i18n: <G extends "bold" | "code" | "colorify" | "mono" | "link" | "italic" | "strike" | "underline" | "mark" | "quote" | "text" | "html" | "cut" | "table" | "image" | "code_inline" | "list" | "heading" | "note" | "file" | "checkbox" | "emoji" | "gpt" | "heading1" | "heading2" | "heading3" | "heading4" | "heading5" | "heading6" | "math_block" | "math_inline" | "mermaid" | "redo" | "tabs" | "undo" | "codeblock" | "math" | "colorify__color_blue" | "colorify__color_default" | "colorify__color_gray" | "colorify__color_green" | "colorify__color_orange" | "colorify__color_red" | "colorify__color_violet" | "colorify__color_yellow" | "colorify__group_text" | "emoji__hint" | "folding-heading" | "folding-heading__hint" | "hrule" | "list__action_lift" | "list__action_sink" | "list_action_disabled" | "more_action" | "move_list" | "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;
|
|
@@ -46,6 +46,7 @@ export declare const i18n: <G extends "bold" | "code" | "colorify" | "mono" | "l
|
|
|
46
46
|
mermaid: string;
|
|
47
47
|
mono: string;
|
|
48
48
|
more_action: string;
|
|
49
|
+
move_list: string;
|
|
49
50
|
note: string;
|
|
50
51
|
olist: string;
|
|
51
52
|
quote: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const i18n: <G extends "remove" | "info" | "
|
|
1
|
+
export declare const i18n: <G extends "remove" | "info" | "tip" | "warning" | "alert", S extends string>(key: G | (string extends S ? S : never), params?: {
|
|
2
2
|
[key: string]: any;
|
|
3
3
|
} | undefined) => S extends G ? {
|
|
4
4
|
info: string;
|
package/build/esm/index.d.ts
CHANGED
package/build/esm/index.js
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CompletionContext, CompletionResult } from '@codemirror/autocomplete';
|
|
2
|
+
export declare const emptyRowSnippetTemplate = " \n\n";
|
|
3
|
+
export declare const emptyRowSnippet: (editor: {
|
|
4
|
+
state: import("@codemirror/state").EditorState;
|
|
5
|
+
dispatch: (tr: import("@codemirror/state").Transaction) => void;
|
|
6
|
+
}, completion: import("@codemirror/autocomplete").Completion | null, from: number, to: number) => void;
|
|
7
|
+
export declare const emptyRowAutocomplete: {
|
|
8
|
+
autocomplete: (context: CompletionContext) => CompletionResult | null;
|
|
9
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { snippet } from '@codemirror/autocomplete';
|
|
2
|
+
import { i18n } from '../../../../src/i18n/empty-row';
|
|
3
|
+
export const emptyRowSnippetTemplate = ' \n\n';
|
|
4
|
+
export const emptyRowSnippet = snippet(emptyRowSnippetTemplate);
|
|
5
|
+
export const emptyRowAutocomplete = {
|
|
6
|
+
autocomplete: (context) => {
|
|
7
|
+
const word = context.matchBefore(/^.*/);
|
|
8
|
+
if (word === null || word === void 0 ? void 0 : word.text.startsWith('&')) {
|
|
9
|
+
return {
|
|
10
|
+
from: word.from,
|
|
11
|
+
options: [
|
|
12
|
+
{
|
|
13
|
+
label: ' ',
|
|
14
|
+
displayLabel: i18n('snippet.text'),
|
|
15
|
+
type: 'text',
|
|
16
|
+
apply: emptyRowSnippet,
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
},
|
|
23
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { mdAutocomplete } from '../yfm';
|
|
2
|
+
import { emptyRowAutocomplete } from './emptyRow';
|
|
3
|
+
export const getAutocompleteConfig = ({ preserveEmptyRows }) => {
|
|
4
|
+
const autocompleteItems = [];
|
|
5
|
+
if (preserveEmptyRows) {
|
|
6
|
+
autocompleteItems.push(emptyRowAutocomplete);
|
|
7
|
+
}
|
|
8
|
+
autocompleteItems.push(mdAutocomplete);
|
|
9
|
+
return autocompleteItems;
|
|
10
|
+
};
|
|
@@ -33,6 +33,7 @@ export declare type CreateCodemirrorParams = {
|
|
|
33
33
|
yfmLangOptions?: YfmLangOptions;
|
|
34
34
|
autocompletion?: Autocompletion;
|
|
35
35
|
directiveSyntax: DirectiveSyntaxContext;
|
|
36
|
+
preserveEmptyRows: boolean;
|
|
36
37
|
};
|
|
37
38
|
export declare function createCodemirror(params: CreateCodemirrorParams): EditorView;
|
|
38
39
|
export declare function withLogger(action: string, command: StateCommand): StateCommand;
|
|
@@ -6,7 +6,7 @@ import { ActionName } from '../../bundle/config/action-names';
|
|
|
6
6
|
import { logger } from '../../logger';
|
|
7
7
|
import { Action as A, formatter as f } from '../../shortcuts';
|
|
8
8
|
import { DataTransferType, shouldSkipHtmlConversion } from '../../utils/clipboard';
|
|
9
|
-
import { insertImages, insertLink, toH1, toH2, toH3, toH4, toH5, toH6, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline, wrapToCodeBlock, wrapToInlineCode, wrapToYfmCut, wrapToYfmNote, } from '../commands';
|
|
9
|
+
import { insertEmptyRow, insertImages, insertLink, toH1, toH2, toH3, toH4, toH5, toH6, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline, wrapToCodeBlock, wrapToInlineCode, wrapToYfmCut, wrapToYfmNote, } from '../commands';
|
|
10
10
|
import { DirectiveSyntaxFacet } from './directive-facet';
|
|
11
11
|
import { FileUploadHandlerFacet } from './files-upload-facet';
|
|
12
12
|
import { gravityHighlightStyle, gravityTheme } from './gravity';
|
|
@@ -14,9 +14,10 @@ import { MarkdownConverter } from './html-to-markdown/converters';
|
|
|
14
14
|
import { PairingCharactersExtension } from './pairing-chars';
|
|
15
15
|
import { ReactRendererFacet } from './react-facet';
|
|
16
16
|
import { SearchPanelPlugin } from './search-plugin/plugin';
|
|
17
|
+
import { smartReindent } from './smart-reindent';
|
|
17
18
|
import { yfmLang } from './yfm';
|
|
18
19
|
export function createCodemirror(params) {
|
|
19
|
-
const { doc, reactRenderer, onCancel, onScroll, onSubmit, onChange, onDocChange, disabledExtensions = {}, keymaps = [], receiver, yfmLangOptions, extensions: extraExtensions, placeholder: placeholderContent, autocompletion: autocompletionConfig, parseHtmlOnPaste, parseInsertedUrlAsImage, directiveSyntax, } = params;
|
|
20
|
+
const { doc, reactRenderer, onCancel, onScroll, onSubmit, onChange, onDocChange, disabledExtensions = {}, keymaps = [], receiver, yfmLangOptions, extensions: extraExtensions, placeholder: placeholderContent, autocompletion: autocompletionConfig, parseHtmlOnPaste, parseInsertedUrlAsImage, directiveSyntax, preserveEmptyRows, } = params;
|
|
20
21
|
const extensions = [gravityTheme, placeholder(placeholderContent)];
|
|
21
22
|
if (!disabledExtensions.history) {
|
|
22
23
|
extensions.push(history());
|
|
@@ -70,12 +71,16 @@ export function createCodemirror(params) {
|
|
|
70
71
|
var _a;
|
|
71
72
|
if (!event.clipboardData)
|
|
72
73
|
return;
|
|
74
|
+
const { from } = editor.state.selection.main;
|
|
75
|
+
const line = editor.state.doc.lineAt(from);
|
|
76
|
+
const currentLine = line.text;
|
|
73
77
|
// if clipboard contains YFM content - avoid any meddling with pasted content
|
|
74
78
|
// since text/yfm will contain valid markdown
|
|
75
79
|
const yfmContent = event.clipboardData.getData(DataTransferType.Yfm);
|
|
76
80
|
if (yfmContent) {
|
|
77
81
|
event.preventDefault();
|
|
78
|
-
|
|
82
|
+
const reindentedYfmContent = smartReindent(yfmContent, currentLine);
|
|
83
|
+
editor.dispatch(editor.state.replaceSelection(reindentedYfmContent));
|
|
79
84
|
return;
|
|
80
85
|
}
|
|
81
86
|
// checking if a copy buffer content is suitable for convertion
|
|
@@ -100,29 +105,42 @@ export function createCodemirror(params) {
|
|
|
100
105
|
}
|
|
101
106
|
if (parsedMarkdownMarkup !== undefined) {
|
|
102
107
|
event.preventDefault();
|
|
103
|
-
|
|
108
|
+
const reindentedHtmlContent = smartReindent(parsedMarkdownMarkup, currentLine);
|
|
109
|
+
editor.dispatch(editor.state.replaceSelection(reindentedHtmlContent));
|
|
104
110
|
return;
|
|
105
111
|
}
|
|
106
112
|
}
|
|
107
113
|
if (parseInsertedUrlAsImage) {
|
|
108
114
|
const { imageUrl, title } = parseInsertedUrlAsImage((_a = event.clipboardData.getData(DataTransferType.Text)) !== null && _a !== void 0 ? _a : '') || {};
|
|
109
|
-
if (
|
|
110
|
-
|
|
115
|
+
if (imageUrl) {
|
|
116
|
+
event.preventDefault();
|
|
117
|
+
insertImages([
|
|
118
|
+
{
|
|
119
|
+
url: imageUrl,
|
|
120
|
+
alt: title,
|
|
121
|
+
title,
|
|
122
|
+
},
|
|
123
|
+
])(editor);
|
|
111
124
|
}
|
|
125
|
+
}
|
|
126
|
+
// Reindenting pasted plain text
|
|
127
|
+
const pastedText = event.clipboardData.getData(DataTransferType.Text);
|
|
128
|
+
const reindentedText = smartReindent(pastedText, currentLine);
|
|
129
|
+
// but only if there is a need for reindentation
|
|
130
|
+
if (pastedText !== reindentedText) {
|
|
131
|
+
editor.dispatch(editor.state.replaceSelection(reindentedText));
|
|
112
132
|
event.preventDefault();
|
|
113
|
-
insertImages([
|
|
114
|
-
{
|
|
115
|
-
url: imageUrl,
|
|
116
|
-
alt: title,
|
|
117
|
-
title,
|
|
118
|
-
},
|
|
119
|
-
])(editor);
|
|
120
133
|
}
|
|
121
134
|
},
|
|
122
135
|
}), SearchPanelPlugin({
|
|
123
136
|
anchorSelector: '.g-md-search-anchor',
|
|
124
137
|
receiver,
|
|
125
138
|
}));
|
|
139
|
+
if (preserveEmptyRows) {
|
|
140
|
+
extensions.push(keymap.of([
|
|
141
|
+
{ key: f.toCM(A.EmptyRow), run: withLogger(ActionName.emptyRow, insertEmptyRow) },
|
|
142
|
+
]));
|
|
143
|
+
}
|
|
126
144
|
if (params.uploadHandler) {
|
|
127
145
|
extensions.push(FileUploadHandlerFacet.of({
|
|
128
146
|
fn: params.uploadHandler,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { parseMarkers } from './utils';
|
|
2
|
+
/**
|
|
3
|
+
* Reindents pasted text based on the current line's markers
|
|
4
|
+
*/
|
|
5
|
+
export function smartReindent(pastedText, currentLineText) {
|
|
6
|
+
// If current line is empty, return pasted text as is
|
|
7
|
+
if (currentLineText.length === 0) {
|
|
8
|
+
return pastedText;
|
|
9
|
+
}
|
|
10
|
+
// Get markers from current line
|
|
11
|
+
const markers = parseMarkers(currentLineText);
|
|
12
|
+
// If no markers found, return pasted text as is
|
|
13
|
+
if (markers.length === 0) {
|
|
14
|
+
return pastedText;
|
|
15
|
+
}
|
|
16
|
+
// Create indentation for subsequent lines by replacing list markers with spaces
|
|
17
|
+
const subsequentIndent = markers
|
|
18
|
+
.map((marker) => {
|
|
19
|
+
if (marker.match(/^\d{1,6}\. |-|\*|\+/)) {
|
|
20
|
+
return ' '.repeat(marker.length);
|
|
21
|
+
}
|
|
22
|
+
return marker;
|
|
23
|
+
})
|
|
24
|
+
.join('');
|
|
25
|
+
// Split and process the pasted text
|
|
26
|
+
const lines = pastedText.split('\n');
|
|
27
|
+
const reindentedText = lines
|
|
28
|
+
.map((line, index) => {
|
|
29
|
+
// First line doesn't need indentation
|
|
30
|
+
if (index === 0) {
|
|
31
|
+
return line;
|
|
32
|
+
}
|
|
33
|
+
// Add indentation to all subsequent lines, including empty ones
|
|
34
|
+
return subsequentIndent + line;
|
|
35
|
+
})
|
|
36
|
+
.join('\n');
|
|
37
|
+
return reindentedText;
|
|
38
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses markdown-style markers from the start of a line
|
|
3
|
+
* Returns an array of markers found:
|
|
4
|
+
* - ' ' for indentation
|
|
5
|
+
* - '> ' for blockquotes
|
|
6
|
+
* - '* ' or '- ' for list items
|
|
7
|
+
* - '1. ' for numbered lists
|
|
8
|
+
*
|
|
9
|
+
* Example inputs:
|
|
10
|
+
* " * list" -> [' ', '* ']
|
|
11
|
+
* "> quoted" -> ['> ']
|
|
12
|
+
* " nested" -> [' ', ' ']
|
|
13
|
+
* "1. list" -> ['1. ']
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseMarkers(text: string): string[];
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses markdown-style markers from the start of a line
|
|
3
|
+
* Returns an array of markers found:
|
|
4
|
+
* - ' ' for indentation
|
|
5
|
+
* - '> ' for blockquotes
|
|
6
|
+
* - '* ' or '- ' for list items
|
|
7
|
+
* - '1. ' for numbered lists
|
|
8
|
+
*
|
|
9
|
+
* Example inputs:
|
|
10
|
+
* " * list" -> [' ', '* ']
|
|
11
|
+
* "> quoted" -> ['> ']
|
|
12
|
+
* " nested" -> [' ', ' ']
|
|
13
|
+
* "1. list" -> ['1. ']
|
|
14
|
+
*/
|
|
15
|
+
export function parseMarkers(text) {
|
|
16
|
+
const markers = [];
|
|
17
|
+
let pos = 0;
|
|
18
|
+
while (pos < text.length) {
|
|
19
|
+
// Handle code block (4 spaces)
|
|
20
|
+
if (pos + 3 < text.length &&
|
|
21
|
+
text[pos] === ' ' &&
|
|
22
|
+
text[pos + 1] === ' ' &&
|
|
23
|
+
text[pos + 2] === ' ' &&
|
|
24
|
+
text[pos + 3] === ' ') {
|
|
25
|
+
markers.push(' ');
|
|
26
|
+
pos += 4;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
// Handle numbered lists (1-6 digits followed by dot and space)
|
|
30
|
+
if (/^\d{1,6}\. /.test(text.slice(pos))) {
|
|
31
|
+
const match = text.slice(pos).match(/^(\d{1,6}\. )/);
|
|
32
|
+
if (match) {
|
|
33
|
+
markers.push(match[1]);
|
|
34
|
+
pos += match[1].length;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Handle block quotes and list markers
|
|
39
|
+
if (text[pos] === '>' || text[pos] === '-' || text[pos] === '*' || text[pos] === '+') {
|
|
40
|
+
if (pos + 1 < text.length && text[pos + 1] === ' ') {
|
|
41
|
+
markers.push(text[pos] + ' ');
|
|
42
|
+
pos += 2;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Handle single space (last priority)
|
|
47
|
+
if (text[pos] === ' ') {
|
|
48
|
+
markers.push(' ');
|
|
49
|
+
pos += 1;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
return markers;
|
|
55
|
+
}
|