@doist/typist 1.0.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/CHANGELOG.md +9 -0
- package/CODE_OF_CONDUCT.md +83 -0
- package/CONTRIBUTING.md +123 -0
- package/LICENSE +21 -0
- package/README.md +74 -0
- package/dist/components/typist-editor.d.ts +173 -0
- package/dist/components/typist-editor.d.ts.map +1 -0
- package/dist/components/typist-editor.helper.d.ts +22 -0
- package/dist/components/typist-editor.helper.d.ts.map +1 -0
- package/dist/components/typist-editor.helper.js +26 -0
- package/dist/components/typist-editor.js +160 -0
- package/dist/constants/common.d.ts +10 -0
- package/dist/constants/common.d.ts.map +1 -0
- package/dist/constants/common.js +9 -0
- package/dist/constants/extension-priorities.d.ts +26 -0
- package/dist/constants/extension-priorities.d.ts.map +1 -0
- package/dist/constants/extension-priorities.js +25 -0
- package/dist/constants/regular-expressions.d.ts +6 -0
- package/dist/constants/regular-expressions.d.ts.map +1 -0
- package/dist/constants/regular-expressions.js +5 -0
- package/dist/extensions/core/extra-editor-commands/commands/extend-word-range.d.ts +24 -0
- package/dist/extensions/core/extra-editor-commands/commands/extend-word-range.d.ts.map +1 -0
- package/dist/extensions/core/extra-editor-commands/commands/extend-word-range.js +32 -0
- package/dist/extensions/core/extra-editor-commands/commands/insert-markdown-content.d.ts +28 -0
- package/dist/extensions/core/extra-editor-commands/commands/insert-markdown-content.d.ts.map +1 -0
- package/dist/extensions/core/extra-editor-commands/commands/insert-markdown-content.js +25 -0
- package/dist/extensions/core/extra-editor-commands/extra-editor-commands.d.ts +9 -0
- package/dist/extensions/core/extra-editor-commands/extra-editor-commands.d.ts.map +1 -0
- package/dist/extensions/core/extra-editor-commands/extra-editor-commands.js +18 -0
- package/dist/extensions/core/view-event-handlers.d.ts +33 -0
- package/dist/extensions/core/view-event-handlers.d.ts.map +1 -0
- package/dist/extensions/core/view-event-handlers.js +35 -0
- package/dist/extensions/plain-text/paste-multiline-text.d.ts +10 -0
- package/dist/extensions/plain-text/paste-multiline-text.d.ts.map +1 -0
- package/dist/extensions/plain-text/paste-multiline-text.js +66 -0
- package/dist/extensions/plain-text/plain-text-document.d.ts +17 -0
- package/dist/extensions/plain-text/plain-text-document.d.ts.map +1 -0
- package/dist/extensions/plain-text/plain-text-document.js +17 -0
- package/dist/extensions/plain-text/plain-text-kit.d.ts +42 -0
- package/dist/extensions/plain-text/plain-text-kit.d.ts.map +1 -0
- package/dist/extensions/plain-text/plain-text-kit.js +47 -0
- package/dist/extensions/plain-text/plain-text-paragraph.d.ts +9 -0
- package/dist/extensions/plain-text/plain-text-paragraph.d.ts.map +1 -0
- package/dist/extensions/plain-text/plain-text-paragraph.js +13 -0
- package/dist/extensions/plain-text/smart-markdown-typing/plugins/smart-lists.d.ts +9 -0
- package/dist/extensions/plain-text/smart-markdown-typing/plugins/smart-lists.d.ts.map +1 -0
- package/dist/extensions/plain-text/smart-markdown-typing/plugins/smart-lists.js +89 -0
- package/dist/extensions/plain-text/smart-markdown-typing/plugins/smart-select-wrap.d.ts +9 -0
- package/dist/extensions/plain-text/smart-markdown-typing/plugins/smart-select-wrap.d.ts.map +1 -0
- package/dist/extensions/plain-text/smart-markdown-typing/plugins/smart-select-wrap.js +49 -0
- package/dist/extensions/plain-text/smart-markdown-typing/plugins/smart-url-pasting.d.ts +9 -0
- package/dist/extensions/plain-text/smart-markdown-typing/plugins/smart-url-pasting.d.ts.map +1 -0
- package/dist/extensions/plain-text/smart-markdown-typing/plugins/smart-url-pasting.js +43 -0
- package/dist/extensions/plain-text/smart-markdown-typing/smart-markdown-typing.d.ts +8 -0
- package/dist/extensions/plain-text/smart-markdown-typing/smart-markdown-typing.d.ts.map +1 -0
- package/dist/extensions/plain-text/smart-markdown-typing/smart-markdown-typing.js +17 -0
- package/dist/extensions/rich-text/bold-and-italics.d.ts +8 -0
- package/dist/extensions/rich-text/bold-and-italics.d.ts.map +1 -0
- package/dist/extensions/rich-text/bold-and-italics.js +40 -0
- package/dist/extensions/rich-text/curvenote-codemark.d.ts +11 -0
- package/dist/extensions/rich-text/curvenote-codemark.d.ts.map +1 -0
- package/dist/extensions/rich-text/curvenote-codemark.js +18 -0
- package/dist/extensions/rich-text/paste-emojis.d.ts +9 -0
- package/dist/extensions/rich-text/paste-emojis.d.ts.map +1 -0
- package/dist/extensions/rich-text/paste-emojis.js +28 -0
- package/dist/extensions/rich-text/paste-markdown.d.ts +11 -0
- package/dist/extensions/rich-text/paste-markdown.d.ts.map +1 -0
- package/dist/extensions/rich-text/paste-markdown.js +68 -0
- package/dist/extensions/rich-text/rich-text-document.d.ts +17 -0
- package/dist/extensions/rich-text/rich-text-document.d.ts.map +1 -0
- package/dist/extensions/rich-text/rich-text-document.js +17 -0
- package/dist/extensions/rich-text/rich-text-image.d.ts +80 -0
- package/dist/extensions/rich-text/rich-text-image.d.ts.map +1 -0
- package/dist/extensions/rich-text/rich-text-image.js +109 -0
- package/dist/extensions/rich-text/rich-text-kit.d.ts +129 -0
- package/dist/extensions/rich-text/rich-text-kit.d.ts.map +1 -0
- package/dist/extensions/rich-text/rich-text-kit.js +130 -0
- package/dist/extensions/rich-text/rich-text-link.d.ts +10 -0
- package/dist/extensions/rich-text/rich-text-link.d.ts.map +1 -0
- package/dist/extensions/rich-text/rich-text-link.js +102 -0
- package/dist/extensions/shared/copy-markdown-source.d.ts +20 -0
- package/dist/extensions/shared/copy-markdown-source.d.ts.map +1 -0
- package/dist/extensions/shared/copy-markdown-source.js +35 -0
- package/dist/extensions/shared/paste-singleline-text.d.ts +10 -0
- package/dist/extensions/shared/paste-singleline-text.d.ts.map +1 -0
- package/dist/extensions/shared/paste-singleline-text.js +43 -0
- package/dist/factories/create-suggestion-extension.d.ts +121 -0
- package/dist/factories/create-suggestion-extension.d.ts.map +1 -0
- package/dist/factories/create-suggestion-extension.js +149 -0
- package/dist/helpers/dom.d.ts +8 -0
- package/dist/helpers/dom.d.ts.map +1 -0
- package/dist/helpers/dom.js +9 -0
- package/dist/helpers/schema.d.ts +19 -0
- package/dist/helpers/schema.d.ts.map +1 -0
- package/dist/helpers/schema.js +21 -0
- package/dist/helpers/serializer.d.ts +11 -0
- package/dist/helpers/serializer.d.ts.map +1 -0
- package/dist/helpers/serializer.js +16 -0
- package/dist/hooks/use-editor.d.ts +19 -0
- package/dist/hooks/use-editor.d.ts.map +1 -0
- package/dist/hooks/use-editor.js +46 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/serializers/html/extensions/checkbox.d.ts +8 -0
- package/dist/serializers/html/extensions/checkbox.d.ts.map +1 -0
- package/dist/serializers/html/extensions/checkbox.js +12 -0
- package/dist/serializers/html/extensions/code.d.ts +9 -0
- package/dist/serializers/html/extensions/code.d.ts.map +1 -0
- package/dist/serializers/html/extensions/code.js +20 -0
- package/dist/serializers/html/extensions/html.d.ts +10 -0
- package/dist/serializers/html/extensions/html.d.ts.map +1 -0
- package/dist/serializers/html/extensions/html.js +15 -0
- package/dist/serializers/html/extensions/link.d.ts +11 -0
- package/dist/serializers/html/extensions/link.d.ts.map +1 -0
- package/dist/serializers/html/extensions/link.js +28 -0
- package/dist/serializers/html/extensions/paragraph.d.ts +12 -0
- package/dist/serializers/html/extensions/paragraph.d.ts.map +1 -0
- package/dist/serializers/html/extensions/paragraph.js +51 -0
- package/dist/serializers/html/extensions/task-list.d.ts +9 -0
- package/dist/serializers/html/extensions/task-list.d.ts.map +1 -0
- package/dist/serializers/html/extensions/task-list.js +31 -0
- package/dist/serializers/html/html.d.ts +27 -0
- package/dist/serializers/html/html.d.ts.map +1 -0
- package/dist/serializers/html/html.js +129 -0
- package/dist/serializers/markdown/markdown.d.ts +40 -0
- package/dist/serializers/markdown/markdown.d.ts.map +1 -0
- package/dist/serializers/markdown/markdown.js +126 -0
- package/dist/serializers/markdown/plugins/image.d.ts +12 -0
- package/dist/serializers/markdown/plugins/image.d.ts.map +1 -0
- package/dist/serializers/markdown/plugins/image.js +31 -0
- package/dist/serializers/markdown/plugins/list-item.d.ts +14 -0
- package/dist/serializers/markdown/plugins/list-item.d.ts.map +1 -0
- package/dist/serializers/markdown/plugins/list-item.js +41 -0
- package/dist/serializers/markdown/plugins/paragraph.d.ts +12 -0
- package/dist/serializers/markdown/plugins/paragraph.d.ts.map +1 -0
- package/dist/serializers/markdown/plugins/paragraph.js +18 -0
- package/dist/serializers/markdown/plugins/strikethrough.d.ts +13 -0
- package/dist/serializers/markdown/plugins/strikethrough.d.ts.map +1 -0
- package/dist/serializers/markdown/plugins/strikethrough.js +23 -0
- package/dist/serializers/markdown/plugins/suggestion.d.ts +11 -0
- package/dist/serializers/markdown/plugins/suggestion.d.ts.map +1 -0
- package/dist/serializers/markdown/plugins/suggestion.js +21 -0
- package/dist/serializers/markdown/plugins/task-item.d.ts +14 -0
- package/dist/serializers/markdown/plugins/task-item.d.ts.map +1 -0
- package/dist/serializers/markdown/plugins/task-item.js +39 -0
- package/package.json +146 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
import { HistoryOptions } from '@tiptap/extension-history';
|
|
3
|
+
import type { PlainTextDocumentOptions } from './plain-text-document';
|
|
4
|
+
import type { PlainTextParagraphOptions } from './plain-text-paragraph';
|
|
5
|
+
/**
|
|
6
|
+
* The options available to customize the `PlainTextKit` extension.
|
|
7
|
+
*/
|
|
8
|
+
declare type PlainTextKitOptions = {
|
|
9
|
+
/**
|
|
10
|
+
* Set options for the `Document` extension, or `false` to disable.
|
|
11
|
+
*/
|
|
12
|
+
document: Partial<PlainTextDocumentOptions> | false;
|
|
13
|
+
/**
|
|
14
|
+
* Set options for the `History` extension, or `false` to disable.
|
|
15
|
+
*/
|
|
16
|
+
history: Partial<HistoryOptions> | false;
|
|
17
|
+
/**
|
|
18
|
+
* Set options for the `Paragraph` extension, or `false` to disable.
|
|
19
|
+
*/
|
|
20
|
+
paragraph: Partial<PlainTextParagraphOptions> | false;
|
|
21
|
+
/**
|
|
22
|
+
* Set to `false` to disable the `Text` extension.
|
|
23
|
+
*/
|
|
24
|
+
text: false;
|
|
25
|
+
/**
|
|
26
|
+
* Set to `false` to disable the `Typography` extension.
|
|
27
|
+
*/
|
|
28
|
+
typography: false;
|
|
29
|
+
/**
|
|
30
|
+
* Set to `false` to disable the `SmartMarkdownTyping` extension.
|
|
31
|
+
*/
|
|
32
|
+
smartMarkdownTyping: false;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* The `PlainTextKit` extension is a collection of the minimal required extensions to have a basic
|
|
36
|
+
* plain-text editor working. This extension is based on the official `StarterKit` extension
|
|
37
|
+
* implementation, allowing almost every extension to be customized or disabled.
|
|
38
|
+
*/
|
|
39
|
+
declare const PlainTextKit: Extension<PlainTextKitOptions, any>;
|
|
40
|
+
export { PlainTextKit };
|
|
41
|
+
export type { PlainTextKitOptions };
|
|
42
|
+
//# sourceMappingURL=plain-text-kit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plain-text-kit.d.ts","sourceRoot":"","sources":["../../../src/extensions/plain-text/plain-text-kit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAW,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAanE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAA;AACrE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAA;AAEvE;;GAEG;AACH,aAAK,mBAAmB,GAAG;IACvB;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC,wBAAwB,CAAC,GAAG,KAAK,CAAA;IAEnD;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,KAAK,CAAA;IAExC;;OAEG;IACH,SAAS,EAAE,OAAO,CAAC,yBAAyB,CAAC,GAAG,KAAK,CAAA;IAErD;;OAEG;IACH,IAAI,EAAE,KAAK,CAAA;IAEX;;OAEG;IACH,UAAU,EAAE,KAAK,CAAA;IAEjB;;OAEG;IACH,mBAAmB,EAAE,KAAK,CAAA;CAC7B,CAAA;AAED;;;;GAIG;AACH,QAAA,MAAM,YAAY,qCAyChB,CAAA;AAEF,OAAO,EAAE,YAAY,EAAE,CAAA;AAEvB,YAAY,EAAE,mBAAmB,EAAE,CAAA"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
import { History } from '@tiptap/extension-history';
|
|
3
|
+
import { Text } from '@tiptap/extension-text';
|
|
4
|
+
import { Typography } from '@tiptap/extension-typography';
|
|
5
|
+
import { CopyMarkdownSource } from '../shared/copy-markdown-source';
|
|
6
|
+
import { PasteSinglelineText } from '../shared/paste-singleline-text';
|
|
7
|
+
import { SmartMarkdownTyping } from './smart-markdown-typing/smart-markdown-typing';
|
|
8
|
+
import { PasteMultilineText } from './paste-multiline-text';
|
|
9
|
+
import { PlainTextDocument } from './plain-text-document';
|
|
10
|
+
import { PlainTextParagraph } from './plain-text-paragraph';
|
|
11
|
+
/**
|
|
12
|
+
* The `PlainTextKit` extension is a collection of the minimal required extensions to have a basic
|
|
13
|
+
* plain-text editor working. This extension is based on the official `StarterKit` extension
|
|
14
|
+
* implementation, allowing almost every extension to be customized or disabled.
|
|
15
|
+
*/
|
|
16
|
+
const PlainTextKit = Extension.create({
|
|
17
|
+
name: 'plainTextKit',
|
|
18
|
+
addExtensions() {
|
|
19
|
+
const extensions = [];
|
|
20
|
+
if (this.options.document !== false) {
|
|
21
|
+
extensions.push(PlainTextDocument.configure(this.options?.document),
|
|
22
|
+
// Supports copying the underlying Markdown source to the clipboard
|
|
23
|
+
CopyMarkdownSource,
|
|
24
|
+
// Supports pasting plain-text into both a singleline and multiline editor
|
|
25
|
+
this.options?.document?.multiline === false
|
|
26
|
+
? PasteSinglelineText
|
|
27
|
+
: PasteMultilineText);
|
|
28
|
+
}
|
|
29
|
+
if (this.options.history !== false) {
|
|
30
|
+
extensions.push(History.configure(this.options?.history));
|
|
31
|
+
}
|
|
32
|
+
if (this.options.paragraph !== false) {
|
|
33
|
+
extensions.push(PlainTextParagraph.configure(this.options?.paragraph));
|
|
34
|
+
}
|
|
35
|
+
if (this.options.text !== false) {
|
|
36
|
+
extensions.push(Text);
|
|
37
|
+
}
|
|
38
|
+
if (this.options.typography !== false) {
|
|
39
|
+
extensions.push(Typography);
|
|
40
|
+
}
|
|
41
|
+
if (this.options.smartMarkdownTyping !== false) {
|
|
42
|
+
extensions.push(SmartMarkdownTyping);
|
|
43
|
+
}
|
|
44
|
+
return extensions;
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
export { PlainTextKit };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ParagraphOptions } from '@tiptap/extension-paragraph';
|
|
2
|
+
/**
|
|
3
|
+
* Custom extension that extends the built-in `Paragraph` extension to add an additional keyboard
|
|
4
|
+
* shortcut to insert a newline (needed to behave more closely to the `<textarea>` component).
|
|
5
|
+
*/
|
|
6
|
+
declare const PlainTextParagraph: import("@tiptap/core").Node<ParagraphOptions, any>;
|
|
7
|
+
export { PlainTextParagraph };
|
|
8
|
+
export type { ParagraphOptions as PlainTextParagraphOptions };
|
|
9
|
+
//# sourceMappingURL=plain-text-paragraph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plain-text-paragraph.d.ts","sourceRoot":"","sources":["../../../src/extensions/plain-text/plain-text-paragraph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AAEzE;;;GAGG;AACH,QAAA,MAAM,kBAAkB,oDAMtB,CAAA;AAEF,OAAO,EAAE,kBAAkB,EAAE,CAAA;AAE7B,YAAY,EAAE,gBAAgB,IAAI,yBAAyB,EAAE,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Paragraph } from '@tiptap/extension-paragraph';
|
|
2
|
+
/**
|
|
3
|
+
* Custom extension that extends the built-in `Paragraph` extension to add an additional keyboard
|
|
4
|
+
* shortcut to insert a newline (needed to behave more closely to the `<textarea>` component).
|
|
5
|
+
*/
|
|
6
|
+
const PlainTextParagraph = Paragraph.extend({
|
|
7
|
+
addKeyboardShortcuts() {
|
|
8
|
+
return {
|
|
9
|
+
'Shift-Enter': () => this.editor.commands.enter(),
|
|
10
|
+
};
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
export { PlainTextParagraph };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Plugin } from 'prosemirror-state';
|
|
2
|
+
/**
|
|
3
|
+
* This plugin provides a more plesant typing experience for both standard and task lists, adding
|
|
4
|
+
* the list marker automatically when pressing the `Enter` key, and it also supports list items
|
|
5
|
+
* indentation with the `Tab` and `Shift+Tab` keys, forward and backward, respectively.
|
|
6
|
+
*/
|
|
7
|
+
declare const smartLists: Plugin<any>;
|
|
8
|
+
export { smartLists };
|
|
9
|
+
//# sourceMappingURL=smart-lists.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smart-lists.d.ts","sourceRoot":"","sources":["../../../../../src/extensions/plain-text/smart-markdown-typing/plugins/smart-lists.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAa,MAAM,mBAAmB,CAAA;AAsBrD;;;;GAIG;AACH,QAAA,MAAM,UAAU,aAsFd,CAAA;AAEF,OAAO,EAAE,UAAU,EAAE,CAAA"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Plugin, PluginKey } from 'prosemirror-state';
|
|
2
|
+
import { isMultilineDocument } from '../../../../helpers/schema';
|
|
3
|
+
/**
|
|
4
|
+
* A list of the allowed keys that might trigger smart typing.
|
|
5
|
+
*/
|
|
6
|
+
const ALLOWED_KEYS = ['Enter', 'Tab'];
|
|
7
|
+
/**
|
|
8
|
+
* The standard and task list item regex for smart typing triggers.
|
|
9
|
+
*/
|
|
10
|
+
const REGEX_LIST_ITEM = /^( *(?:(?:\*|-)(?: \[[ x]\])?|\d+\.) )[^\n]*$/i;
|
|
11
|
+
/**
|
|
12
|
+
* A string with the minimum required spaces to properly indent list items.
|
|
13
|
+
*/
|
|
14
|
+
const INDENT_SPACES = ' ';
|
|
15
|
+
/**
|
|
16
|
+
* This plugin provides a more plesant typing experience for both standard and task lists, adding
|
|
17
|
+
* the list marker automatically when pressing the `Enter` key, and it also supports list items
|
|
18
|
+
* indentation with the `Tab` and `Shift+Tab` keys, forward and backward, respectively.
|
|
19
|
+
*/
|
|
20
|
+
const smartLists = new Plugin({
|
|
21
|
+
key: new PluginKey('smartLists'),
|
|
22
|
+
props: {
|
|
23
|
+
handleKeyDown(view, event) {
|
|
24
|
+
const { schema } = view.state;
|
|
25
|
+
const { selection, tr } = view.state;
|
|
26
|
+
// Do not handle the event if not in a multiline document
|
|
27
|
+
if (!isMultilineDocument(schema)) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
// Do not handle the event if allowed keys were not pressed
|
|
31
|
+
if (!ALLOWED_KEYS.includes(event.key)) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
const match = selection.$from.nodeBefore?.text?.match(REGEX_LIST_ITEM);
|
|
35
|
+
// Do not handle the event if a list/task item was not found
|
|
36
|
+
if (!match) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
// Insert a new list marker with `Enter`?
|
|
40
|
+
if (event.key === 'Enter') {
|
|
41
|
+
// If the whole match is different from the first group match, the list item is not
|
|
42
|
+
// empty, and a new list marker is inserted; If they are equal, the list item is
|
|
43
|
+
// empty, and the list marker is deleted
|
|
44
|
+
if (match[0] !== match[1]) {
|
|
45
|
+
// Attempt to parse the first group match as an ordered list item marker
|
|
46
|
+
const orderedListItemMarkerIndex = parseInt(match[1], 10);
|
|
47
|
+
// Increment the ordered list item marker by 1 if it's a number, otherwise
|
|
48
|
+
// use the first group match as the list item marker
|
|
49
|
+
const nextListItemMarker = orderedListItemMarkerIndex
|
|
50
|
+
? `${orderedListItemMarkerIndex + 1}. `
|
|
51
|
+
: // Make sure the next task item marker is unchecked
|
|
52
|
+
match[1].replace(/\[x\]/i, '[ ]');
|
|
53
|
+
view.dispatch(tr
|
|
54
|
+
.replaceSelectionWith(schema.node('paragraph', {}, schema.text(nextListItemMarker)))
|
|
55
|
+
.scrollIntoView());
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
view.dispatch(tr.delete(selection.from - match[1].length, selection.to));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Indent the list item with `Tab` or `Shift+Tab`?
|
|
62
|
+
else if (event.key === 'Tab') {
|
|
63
|
+
// If the whole match is different from the first group match, the text cursor is
|
|
64
|
+
// not at the beginning of the list item (i.e., `* |<Text>`, where the pipe is), and
|
|
65
|
+
// the event is not handled (for now this restriction is disabled)
|
|
66
|
+
// if (match[0] !== match[1]) {
|
|
67
|
+
// return false
|
|
68
|
+
// }
|
|
69
|
+
// Indent the list item forward or backward?
|
|
70
|
+
if (!event.shiftKey) {
|
|
71
|
+
// Indent the list item forward
|
|
72
|
+
view.dispatch(tr
|
|
73
|
+
.insertText(INDENT_SPACES, selection.from - match[0].length)
|
|
74
|
+
.scrollIntoView());
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
// Indent the list item backward if the whole match starts with a whitespace,
|
|
78
|
+
// otherwise do nothing as the list item is already at the start of the line
|
|
79
|
+
if (match[0].startsWith(INDENT_SPACES)) {
|
|
80
|
+
view.dispatch(tr.delete(selection.from - match[0].length, selection.to - match[0].length + INDENT_SPACES.length));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Suppress the default handling behaviour
|
|
85
|
+
return true;
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
export { smartLists };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Plugin } from 'prosemirror-state';
|
|
2
|
+
/**
|
|
3
|
+
* This plugin wraps a selection with matching symbols based on the typed character, wrapping the
|
|
4
|
+
* selection with the corresponding opening and closing bracket symbols when appropriate. This
|
|
5
|
+
* plugin does not have support for multiple selection ranges.
|
|
6
|
+
*/
|
|
7
|
+
declare const smartSelectWrap: Plugin<any>;
|
|
8
|
+
export { smartSelectWrap };
|
|
9
|
+
//# sourceMappingURL=smart-select-wrap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smart-select-wrap.d.ts","sourceRoot":"","sources":["../../../../../src/extensions/plain-text/smart-markdown-typing/plugins/smart-select-wrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA4B,MAAM,mBAAmB,CAAA;AAsBpE;;;;GAIG;AACH,QAAA,MAAM,eAAe,aA+BnB,CAAA;AAEF,OAAO,EAAE,eAAe,EAAE,CAAA"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Plugin, PluginKey, TextSelection } from 'prosemirror-state';
|
|
2
|
+
/**
|
|
3
|
+
* An object holding the acceptable wrapping symbols. The key represents the trigger character, and
|
|
4
|
+
* the character to be added before the selection, while the value represents the character to be
|
|
5
|
+
* added after the selection.
|
|
6
|
+
*/
|
|
7
|
+
const WRAPPING_SYMBOLS = {
|
|
8
|
+
'*': '*',
|
|
9
|
+
_: '_',
|
|
10
|
+
'~': '~',
|
|
11
|
+
'"': '"',
|
|
12
|
+
"'": "'",
|
|
13
|
+
'`': '`',
|
|
14
|
+
'(': ')',
|
|
15
|
+
'[': ']',
|
|
16
|
+
'{': '}',
|
|
17
|
+
'<': '>',
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* This plugin wraps a selection with matching symbols based on the typed character, wrapping the
|
|
21
|
+
* selection with the corresponding opening and closing bracket symbols when appropriate. This
|
|
22
|
+
* plugin does not have support for multiple selection ranges.
|
|
23
|
+
*/
|
|
24
|
+
const smartSelectWrap = new Plugin({
|
|
25
|
+
key: new PluginKey('smartSelectWrap'),
|
|
26
|
+
props: {
|
|
27
|
+
handleTextInput(view, from, to, symbol) {
|
|
28
|
+
const { selection, tr } = view.state;
|
|
29
|
+
// Do not handle the event if the selection is empty
|
|
30
|
+
if (selection.empty) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
const wrappingSymbol = WRAPPING_SYMBOLS[symbol];
|
|
34
|
+
// Do not handle the event if no wrapping symbol was typed
|
|
35
|
+
if (wrappingSymbol === undefined) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
// Insert wrapping symbols around the selected text
|
|
39
|
+
view.dispatch(tr
|
|
40
|
+
.insertText(symbol, from, from)
|
|
41
|
+
.insertText(wrappingSymbol, to + 1, to + 1)
|
|
42
|
+
.setSelection(TextSelection.create(tr.doc, from + 1, to + 1))
|
|
43
|
+
.scrollIntoView());
|
|
44
|
+
// Suppress the default handling behaviour
|
|
45
|
+
return true;
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
export { smartSelectWrap };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Plugin } from 'prosemirror-state';
|
|
2
|
+
/**
|
|
3
|
+
* This plugin replaces a selection with the pasted URL using proper link syntax; unless the
|
|
4
|
+
* selection is itself a URL, which in that case the selection will just be replaced by the pasted
|
|
5
|
+
* URL. This plugin does not have support for multiple selection ranges.
|
|
6
|
+
*/
|
|
7
|
+
declare const smartUrlPasting: Plugin<any>;
|
|
8
|
+
export { smartUrlPasting };
|
|
9
|
+
//# sourceMappingURL=smart-url-pasting.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smart-url-pasting.d.ts","sourceRoot":"","sources":["../../../../../src/extensions/plain-text/smart-markdown-typing/plugins/smart-url-pasting.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA4B,MAAM,mBAAmB,CAAA;AAcpE;;;;GAIG;AACH,QAAA,MAAM,eAAe,aAsCnB,CAAA;AAEF,OAAO,EAAE,eAAe,EAAE,CAAA"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Plugin, PluginKey, TextSelection } from 'prosemirror-state';
|
|
2
|
+
import { ClipboardDataType } from '../../../../constants/common';
|
|
3
|
+
/**
|
|
4
|
+
* The perfect URL validation regex for Web URLs.
|
|
5
|
+
*
|
|
6
|
+
* @see https://mathiasbynens.be/demo/url-regex
|
|
7
|
+
*/
|
|
8
|
+
const REGEX_WEB_URL = /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$/i;
|
|
9
|
+
/**
|
|
10
|
+
* This plugin replaces a selection with the pasted URL using proper link syntax; unless the
|
|
11
|
+
* selection is itself a URL, which in that case the selection will just be replaced by the pasted
|
|
12
|
+
* URL. This plugin does not have support for multiple selection ranges.
|
|
13
|
+
*/
|
|
14
|
+
const smartUrlPasting = new Plugin({
|
|
15
|
+
key: new PluginKey('smartUrlPasting'),
|
|
16
|
+
props: {
|
|
17
|
+
handlePaste(view, event) {
|
|
18
|
+
const { selection, tr } = view.state;
|
|
19
|
+
// Do not handle the event if the selection is empty
|
|
20
|
+
if (selection.empty) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
// Do not handle the event if the selected text is already a URL
|
|
24
|
+
if (REGEX_WEB_URL.test(selection.$head.parent.textContent)) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
const clipboardText = event.clipboardData?.getData(ClipboardDataType.Text).trim();
|
|
28
|
+
// Do not handle the event if the clipboard text is not a URL
|
|
29
|
+
if (!clipboardText || !REGEX_WEB_URL.test(clipboardText)) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
// Apply the Markdown link syntax to the selected and clipboard text pair
|
|
33
|
+
view.dispatch(tr
|
|
34
|
+
.insertText('[', selection.from, selection.from)
|
|
35
|
+
.insertText(`](${clipboardText})`, selection.to + 1, selection.to + 1)
|
|
36
|
+
.setSelection(TextSelection.create(tr.doc, selection.from + 1, selection.to + 1))
|
|
37
|
+
.scrollIntoView());
|
|
38
|
+
// Suppress the default handling behaviour
|
|
39
|
+
return true;
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
export { smartUrlPasting };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
/**
|
|
3
|
+
* The `SmartMarkdownTyping` extension is a collection of ProseMirror plugins that attempts to mimic
|
|
4
|
+
* a smart GitHub like typing experience, and is only meant to be used with a plain-text editor.
|
|
5
|
+
*/
|
|
6
|
+
declare const SmartMarkdownTyping: Extension<any, any>;
|
|
7
|
+
export { SmartMarkdownTyping };
|
|
8
|
+
//# sourceMappingURL=smart-markdown-typing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smart-markdown-typing.d.ts","sourceRoot":"","sources":["../../../../src/extensions/plain-text/smart-markdown-typing/smart-markdown-typing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAQxC;;;GAGG;AACH,QAAA,MAAM,mBAAmB,qBAMvB,CAAA;AAEF,OAAO,EAAE,mBAAmB,EAAE,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
import { SMART_MARKDOWN_TYPING_PRIORITY } from '../../../constants/extension-priorities';
|
|
3
|
+
import { smartLists } from './plugins/smart-lists';
|
|
4
|
+
import { smartSelectWrap } from './plugins/smart-select-wrap';
|
|
5
|
+
import { smartUrlPasting } from './plugins/smart-url-pasting';
|
|
6
|
+
/**
|
|
7
|
+
* The `SmartMarkdownTyping` extension is a collection of ProseMirror plugins that attempts to mimic
|
|
8
|
+
* a smart GitHub like typing experience, and is only meant to be used with a plain-text editor.
|
|
9
|
+
*/
|
|
10
|
+
const SmartMarkdownTyping = Extension.create({
|
|
11
|
+
name: 'smartMarkdownTyping',
|
|
12
|
+
priority: SMART_MARKDOWN_TYPING_PRIORITY,
|
|
13
|
+
addProseMirrorPlugins() {
|
|
14
|
+
return [smartLists, smartSelectWrap, smartUrlPasting];
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
export { SmartMarkdownTyping };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Mark } from '@tiptap/core';
|
|
2
|
+
/**
|
|
3
|
+
* The `BoldAndItalics` extension adds the ability to use the `***` and `___` Markdown shortcuts
|
|
4
|
+
* when typing and pasting into the editor.
|
|
5
|
+
*/
|
|
6
|
+
declare const BoldAndItalics: Mark<any, any>;
|
|
7
|
+
export { BoldAndItalics };
|
|
8
|
+
//# sourceMappingURL=bold-and-italics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bold-and-italics.d.ts","sourceRoot":"","sources":["../../../src/extensions/rich-text/bold-and-italics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgC,MAAM,cAAc,CAAA;AAOjE;;;GAGG;AACH,QAAA,MAAM,cAAc,gBA6BlB,CAAA;AAEF,OAAO,EAAE,cAAc,EAAE,CAAA"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Mark, markInputRule, markPasteRule } from '@tiptap/core';
|
|
2
|
+
const starInputRegex = /(?:^|\s)((?:\*{3})((?:[^*]+))(?:\*{3}))$/;
|
|
3
|
+
const starPasteRegex = /(?:^|\s)((?:\*{3})((?:[^*]+))(?:\*{3}))/g;
|
|
4
|
+
const underscoreInputRegex = /(?:^|\s)((?:_{3})((?:[^_]+))(?:_{3}))$/;
|
|
5
|
+
const underscorePasteRegex = /(?:^|\s)((?:_{3})((?:[^_]+))(?:_{3}))/g;
|
|
6
|
+
/**
|
|
7
|
+
* The `BoldAndItalics` extension adds the ability to use the `***` and `___` Markdown shortcuts
|
|
8
|
+
* when typing and pasting into the editor.
|
|
9
|
+
*/
|
|
10
|
+
const BoldAndItalics = Mark.create({
|
|
11
|
+
name: 'boldAndItalics',
|
|
12
|
+
renderHTML({ HTMLAttributes }) {
|
|
13
|
+
return ['strong', ['em', HTMLAttributes, 0]];
|
|
14
|
+
},
|
|
15
|
+
addInputRules() {
|
|
16
|
+
return [
|
|
17
|
+
markInputRule({
|
|
18
|
+
find: starInputRegex,
|
|
19
|
+
type: this.type,
|
|
20
|
+
}),
|
|
21
|
+
markInputRule({
|
|
22
|
+
find: underscoreInputRegex,
|
|
23
|
+
type: this.type,
|
|
24
|
+
}),
|
|
25
|
+
];
|
|
26
|
+
},
|
|
27
|
+
addPasteRules() {
|
|
28
|
+
return [
|
|
29
|
+
markPasteRule({
|
|
30
|
+
find: starPasteRegex,
|
|
31
|
+
type: this.type,
|
|
32
|
+
}),
|
|
33
|
+
markPasteRule({
|
|
34
|
+
find: underscorePasteRegex,
|
|
35
|
+
type: this.type,
|
|
36
|
+
}),
|
|
37
|
+
];
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
export { BoldAndItalics };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
/**
|
|
3
|
+
* The `CurvenoteCodemark` extension adds a plugin for ProseMirror that makes it easier to handle,
|
|
4
|
+
* and navigate inline code marks. The plugin creates a fake cursor (if necessary) to show if the
|
|
5
|
+
* next character to be typed will or will not be inside the inline code mark.
|
|
6
|
+
*
|
|
7
|
+
* @see https://github.com/curvenote/prosemirror-codemark
|
|
8
|
+
*/
|
|
9
|
+
declare const CurvenoteCodemark: Extension<any, any>;
|
|
10
|
+
export { CurvenoteCodemark };
|
|
11
|
+
//# sourceMappingURL=curvenote-codemark.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"curvenote-codemark.d.ts","sourceRoot":"","sources":["../../../src/extensions/rich-text/curvenote-codemark.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAGxC;;;;;;GAMG;AACH,QAAA,MAAM,iBAAiB,qBAOrB,CAAA;AAEF,OAAO,EAAE,iBAAiB,EAAE,CAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
import codemark from 'prosemirror-codemark';
|
|
3
|
+
/**
|
|
4
|
+
* The `CurvenoteCodemark` extension adds a plugin for ProseMirror that makes it easier to handle,
|
|
5
|
+
* and navigate inline code marks. The plugin creates a fake cursor (if necessary) to show if the
|
|
6
|
+
* next character to be typed will or will not be inside the inline code mark.
|
|
7
|
+
*
|
|
8
|
+
* @see https://github.com/curvenote/prosemirror-codemark
|
|
9
|
+
*/
|
|
10
|
+
const CurvenoteCodemark = Extension.create({
|
|
11
|
+
name: 'curvenoteCodemark',
|
|
12
|
+
addProseMirrorPlugins() {
|
|
13
|
+
return codemark({
|
|
14
|
+
markType: this.editor.schema.marks.code,
|
|
15
|
+
});
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
export { CurvenoteCodemark };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
/**
|
|
3
|
+
* The `PasteEmojis` extension adds the ability to paste HTML image emojis as unicode characters
|
|
4
|
+
* into the editor, ignoring the HTML image source. This extension works by replacing all `<img>`
|
|
5
|
+
* tags with the emoji unicode character, if one is found in the `alt` attribute.
|
|
6
|
+
*/
|
|
7
|
+
declare const PasteEmojis: Extension<any, any>;
|
|
8
|
+
export { PasteEmojis };
|
|
9
|
+
//# sourceMappingURL=paste-emojis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paste-emojis.d.ts","sourceRoot":"","sources":["../../../src/extensions/rich-text/paste-emojis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAaxC;;;;GAIG;AACH,QAAA,MAAM,WAAW,qBAcf,CAAA;AAEF,OAAO,EAAE,WAAW,EAAE,CAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
import emojiRegex from 'emoji-regex';
|
|
3
|
+
import { Plugin, PluginKey } from 'prosemirror-state';
|
|
4
|
+
// Regular expression to match all emoji symbols and sequences (including textual representations)
|
|
5
|
+
const baseEmojiRegExp = emojiRegex();
|
|
6
|
+
// Regular expression to match `<img>` tags with emoji unicode characters in the `alt` attribute
|
|
7
|
+
const imgWithEmojiRegExp = new RegExp(`<img[^>]+alt="(${baseEmojiRegExp.source})"[^>]+/?>`, baseEmojiRegExp.flags);
|
|
8
|
+
/**
|
|
9
|
+
* The `PasteEmojis` extension adds the ability to paste HTML image emojis as unicode characters
|
|
10
|
+
* into the editor, ignoring the HTML image source. This extension works by replacing all `<img>`
|
|
11
|
+
* tags with the emoji unicode character, if one is found in the `alt` attribute.
|
|
12
|
+
*/
|
|
13
|
+
const PasteEmojis = Extension.create({
|
|
14
|
+
name: 'pasteEmojis',
|
|
15
|
+
addProseMirrorPlugins() {
|
|
16
|
+
return [
|
|
17
|
+
new Plugin({
|
|
18
|
+
key: new PluginKey('pasteEmojis'),
|
|
19
|
+
props: {
|
|
20
|
+
transformPastedHTML(html) {
|
|
21
|
+
return html.replace(imgWithEmojiRegExp, (_, alt) => alt);
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
}),
|
|
25
|
+
];
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
export { PasteEmojis };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
/**
|
|
3
|
+
* The `PasteMarkdown` extension adds the ability to paste Markdown as HTML into the editor,
|
|
4
|
+
* providing full rich-text support to the pasted content. The pasting behavior was inspired from
|
|
5
|
+
* the GitLab implementation, and adapted to our requirements.
|
|
6
|
+
*
|
|
7
|
+
* @see https://gitlab.com/gitlab-org/gitlab/-/blob/v14.10.0-ee/app/assets/javascripts/content_editor/extensions/paste_markdown.js
|
|
8
|
+
*/
|
|
9
|
+
declare const PasteMarkdown: Extension<any, any>;
|
|
10
|
+
export { PasteMarkdown };
|
|
11
|
+
//# sourceMappingURL=paste-markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paste-markdown.d.ts","sourceRoot":"","sources":["../../../src/extensions/rich-text/paste-markdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAexC;;;;;;GAMG;AACH,QAAA,MAAM,aAAa,qBA4EjB,CAAA;AAEF,OAAO,EAAE,aAAa,EAAE,CAAA"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
import { Fragment, Slice } from 'prosemirror-model';
|
|
3
|
+
import { Plugin, PluginKey } from 'prosemirror-state';
|
|
4
|
+
import { ClipboardDataType } from '../../constants/common';
|
|
5
|
+
/**
|
|
6
|
+
* The `PasteMarkdown` extension adds the ability to paste Markdown as HTML into the editor,
|
|
7
|
+
* providing full rich-text support to the pasted content. The pasting behavior was inspired from
|
|
8
|
+
* the GitLab implementation, and adapted to our requirements.
|
|
9
|
+
*
|
|
10
|
+
* @see https://gitlab.com/gitlab-org/gitlab/-/blob/v14.10.0-ee/app/assets/javascripts/content_editor/extensions/paste_markdown.js
|
|
11
|
+
*/
|
|
12
|
+
const PasteMarkdown = Extension.create({
|
|
13
|
+
name: 'pasteMarkdown',
|
|
14
|
+
addProseMirrorPlugins() {
|
|
15
|
+
const { editor } = this;
|
|
16
|
+
return [
|
|
17
|
+
new Plugin({
|
|
18
|
+
key: new PluginKey('pasteMarkdown'),
|
|
19
|
+
props: {
|
|
20
|
+
clipboardTextParser(text) {
|
|
21
|
+
// Override the default parser behavior of splitting text into lines (which
|
|
22
|
+
// does not match the CommonMark spec for handling break lines), and instead
|
|
23
|
+
// return a document slice with a single text node containing the whole
|
|
24
|
+
// clipboard text, so that we can rely on the slice on `handlePaste` below)
|
|
25
|
+
return Slice.maxOpen(Fragment.from(editor.schema.text(text)));
|
|
26
|
+
},
|
|
27
|
+
handlePaste(_, event, slice) {
|
|
28
|
+
const clipboardText = event.clipboardData
|
|
29
|
+
?.getData(ClipboardDataType.Text)
|
|
30
|
+
.trim();
|
|
31
|
+
const clipboardContainsHTML = Boolean(event.clipboardData?.types.some((type) => type === ClipboardDataType.HTML));
|
|
32
|
+
// Unfortunately, the VS Code clipboard data type is not supported by
|
|
33
|
+
// Firefox or Safari, which means that copy/paste experience from VS Code
|
|
34
|
+
// into the editor with any of those browsers is supbar:
|
|
35
|
+
// * The Markdown syntax is not fully converted to rich-text
|
|
36
|
+
// * Code is not detected nor converted to a code-block
|
|
37
|
+
const clipboardContainsVSCodeMetadata = Boolean(event.clipboardData?.types.some((type) => type === ClipboardDataType.VSCode));
|
|
38
|
+
const vsCodeClipboardMetadata = clipboardContainsVSCodeMetadata
|
|
39
|
+
? JSON.parse(event.clipboardData?.getData(ClipboardDataType.VSCode) ||
|
|
40
|
+
'{}')
|
|
41
|
+
: {};
|
|
42
|
+
// Do not handle the paste event if:
|
|
43
|
+
// * The clipboard doesn't contain plain-text
|
|
44
|
+
// * The clipboard HTML content doesn't come with VS Code metadata
|
|
45
|
+
// * The clipboard VS Code metadata does not represent plain-Markdown
|
|
46
|
+
// * The user is pasting inside a code block element
|
|
47
|
+
if (!clipboardText ||
|
|
48
|
+
(clipboardContainsHTML && !clipboardContainsVSCodeMetadata) ||
|
|
49
|
+
(clipboardContainsVSCodeMetadata &&
|
|
50
|
+
vsCodeClipboardMetadata.mode !== 'markdown') ||
|
|
51
|
+
editor.state.selection.$from.parent.type.name === 'codeBlock') {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
// Send the clipboard text through the HTML serializer to convert potential
|
|
55
|
+
// Markdown into HTML, and then insert it into the editor
|
|
56
|
+
editor.commands.insertMarkdownContent(
|
|
57
|
+
// The slice content is used instead of `clipboardText` as the pasted
|
|
58
|
+
// content could have already been transformed by other plugins
|
|
59
|
+
slice.content.textBetween(0, slice.content.size));
|
|
60
|
+
// Suppress the default handling behaviour
|
|
61
|
+
return true;
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
}),
|
|
65
|
+
];
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
export { PasteMarkdown };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The options available to customize the `RichTextDocumentOptions` extension.
|
|
3
|
+
*/
|
|
4
|
+
declare type RichTextDocumentOptions = {
|
|
5
|
+
/**
|
|
6
|
+
* Indicates whether the document accepts multiple lines of input or only a single line.
|
|
7
|
+
*/
|
|
8
|
+
multiline: boolean;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Custom extension that extends the built-in `Document` extension to define a schema for multiline
|
|
12
|
+
* or singleline rich-text documents (as opposed to the multiple block nodes by default).
|
|
13
|
+
*/
|
|
14
|
+
declare const RichTextDocument: import("@tiptap/core").Node<RichTextDocumentOptions, any>;
|
|
15
|
+
export { RichTextDocument };
|
|
16
|
+
export type { RichTextDocumentOptions };
|
|
17
|
+
//# sourceMappingURL=rich-text-document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rich-text-document.d.ts","sourceRoot":"","sources":["../../../src/extensions/rich-text/rich-text-document.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,aAAK,uBAAuB,GAAG;IAC3B;;OAEG;IACH,SAAS,EAAE,OAAO,CAAA;CACrB,CAAA;AAED;;;GAGG;AACH,QAAA,MAAM,gBAAgB,2DAUpB,CAAA;AAEF,OAAO,EAAE,gBAAgB,EAAE,CAAA;AAE3B,YAAY,EAAE,uBAAuB,EAAE,CAAA"}
|