@blocknote/core 0.25.2 → 0.27.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/dist/blocknote.cjs +11 -10
- package/dist/blocknote.cjs.map +1 -1
- package/dist/blocknote.js +3722 -9856
- package/dist/blocknote.js.map +1 -1
- package/dist/comments.cjs +1 -1
- package/dist/comments.cjs.map +1 -1
- package/dist/comments.js +45 -44
- package/dist/comments.js.map +1 -1
- package/dist/en-B7ycW7c8.js +360 -0
- package/dist/en-B7ycW7c8.js.map +1 -0
- package/dist/en-D4taoCs4.cjs +2 -0
- package/dist/en-D4taoCs4.cjs.map +1 -0
- package/dist/locales.cjs +2 -0
- package/dist/locales.cjs.map +1 -0
- package/dist/locales.js +6129 -0
- package/dist/locales.js.map +1 -0
- package/dist/style.css +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/webpack-stats.json +1 -1
- package/package.json +36 -27
- package/src/api/clipboard/__snapshots__/internal/basicBlocks.html +1 -1
- package/src/api/clipboard/__snapshots__/internal/basicBlocksWithProps.html +1 -1
- package/src/api/clipboard/clipboardExternal.test.ts +1 -1
- package/src/api/clipboard/clipboardInternal.test.ts +1 -1
- package/src/api/clipboard/fromClipboard/acceptedMIMETypes.ts +1 -0
- package/src/api/clipboard/fromClipboard/pasteExtension.ts +96 -42
- package/src/api/exporters/html/__snapshots__/codeBlock/contains-newlines/external.html +1 -1
- package/src/api/exporters/html/__snapshots__/codeBlock/contains-newlines/internal.html +1 -1
- package/src/api/exporters/html/__snapshots__/codeBlock/defaultLanguage/external.html +1 -1
- package/src/api/exporters/html/__snapshots__/codeBlock/defaultLanguage/internal.html +1 -1
- package/src/api/exporters/html/__snapshots__/codeBlock/empty/external.html +1 -1
- package/src/api/exporters/html/__snapshots__/codeBlock/empty/internal.html +1 -1
- package/src/api/exporters/html/__snapshots__/codeBlock/python/external.html +1 -1
- package/src/api/exporters/html/__snapshots__/codeBlock/python/internal.html +1 -1
- package/src/api/exporters/html/htmlConversion.test.ts +2 -2
- package/src/api/exporters/html/util/serializeBlocksExternalHTML.ts +4 -4
- package/src/api/exporters/markdown/__snapshots__/codeBlock/defaultLanguage/markdown.md +1 -1
- package/src/api/exporters/markdown/__snapshots__/codeBlock/empty/markdown.md +1 -1
- package/src/api/exporters/markdown/__snapshots__/complex/misc/markdown.md +1 -1
- package/src/api/exporters/markdown/__snapshots__/lists/basic/markdown.md +8 -6
- package/src/api/exporters/markdown/__snapshots__/lists/nested/markdown.md +6 -6
- package/src/api/exporters/markdown/markdownExporter.test.ts +2 -2
- package/src/api/nodeConversions/__snapshots__/nodeConversions.test.ts.snap +2 -2
- package/src/api/nodeConversions/nodeToBlock.ts +1 -0
- package/src/api/parsers/html/__snapshots__/parse-2-tables.json +129 -0
- package/src/api/parsers/html/__snapshots__/parse-codeblocks.json +1 -1
- package/src/api/parsers/html/parseHTML.test.ts +36 -1
- package/src/api/parsers/markdown/__snapshots__/pasted/whitespace bold.json +42 -0
- package/src/api/parsers/markdown/__snapshots__/whitespace bold.json +19 -0
- package/src/api/parsers/markdown/detectMarkdown.ts +60 -0
- package/src/api/parsers/markdown/parseMarkdown.test.ts +7 -2
- package/src/api/parsers/markdown/parseMarkdown.ts +19 -18
- package/src/api/testUtil/cases/defaultSchema.ts +13 -0
- package/src/blocks/CodeBlockContent/CodeBlockContent.ts +100 -69
- package/src/blocks/QuoteBlockContent/QuoteBlockContent.ts +98 -0
- package/src/blocks/TableBlockContent/TableExtension.ts +1 -1
- package/src/blocks/defaultBlocks.ts +2 -2
- package/src/comments/threadstore/yjs/YjsThreadStore.ts +1 -0
- package/src/comments/threadstore/yjs/yjsHelpers.ts +3 -1
- package/src/comments/types.ts +4 -0
- package/src/editor/Block.css +14 -1
- package/src/editor/BlockNoteEditor.ts +103 -11
- package/src/editor/BlockNoteExtensions.ts +18 -4
- package/src/editor/BlockNoteTipTapEditor.ts +18 -7
- package/src/extensions/Comments/CommentsPlugin.ts +77 -30
- package/src/extensions/HardBreak/HardBreak.ts +35 -0
- package/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts +100 -3
- package/src/extensions/SideMenu/dragging.ts +13 -0
- package/src/extensions/SuggestionMenu/SuggestionPlugin.ts +3 -1
- package/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts +18 -2
- package/src/extensions/TableHandles/TableHandlesPlugin.ts +24 -23
- package/src/i18n/index.ts +2 -0
- package/src/i18n/locales/ar.ts +10 -0
- package/src/i18n/locales/de.ts +21 -1
- package/src/i18n/locales/en.ts +10 -0
- package/src/i18n/locales/es.ts +21 -1
- package/src/i18n/locales/fr.ts +10 -0
- package/src/i18n/locales/hr.ts +27 -4
- package/src/i18n/locales/is.ts +10 -0
- package/src/i18n/locales/it.ts +21 -1
- package/src/i18n/locales/ja.ts +10 -0
- package/src/i18n/locales/ko.ts +10 -0
- package/src/i18n/locales/nl.ts +10 -0
- package/src/i18n/locales/no.ts +10 -0
- package/src/i18n/locales/pl.ts +10 -0
- package/src/i18n/locales/pt.ts +10 -0
- package/src/i18n/locales/ru.ts +10 -0
- package/src/i18n/locales/uk.ts +10 -0
- package/src/i18n/locales/vi.ts +10 -0
- package/src/i18n/locales/zh.ts +10 -0
- package/src/index.ts +2 -3
- package/src/locales.ts +1 -0
- package/src/schema/blocks/types.ts +1 -0
- package/types/src/api/blockManipulation/commands/updateBlock/updateBlock.d.ts +1 -1
- package/types/src/api/blockManipulation/setupTestEnv.d.ts +34 -2
- package/types/src/api/clipboard/fromClipboard/acceptedMIMETypes.d.ts +1 -1
- package/types/src/api/clipboard/fromClipboard/fileDropExtension.d.ts +2 -2
- package/types/src/api/clipboard/fromClipboard/pasteExtension.d.ts +3 -3
- package/types/src/api/clipboard/testUtil.d.ts +66 -34
- package/types/src/api/clipboard/toClipboard/copyExtension.d.ts +1 -1
- package/types/src/api/exporters/html/externalHTMLExporter.d.ts +2 -2
- package/types/src/api/exporters/html/internalHTMLSerializer.d.ts +2 -2
- package/types/src/api/exporters/html/util/serializeBlocksExternalHTML.d.ts +1 -1
- package/types/src/api/exporters/html/util/serializeBlocksInternalHTML.d.ts +1 -1
- package/types/src/api/parsers/markdown/detectMarkdown.d.ts +6 -0
- package/types/src/api/parsers/markdown/parseMarkdown.d.ts +1 -0
- package/types/src/api/testUtil/cases/customBlocks.d.ts +72 -40
- package/types/src/api/testUtil/cases/customInlineContent.d.ts +34 -2
- package/types/src/api/testUtil/cases/customStyles.d.ts +34 -2
- package/types/src/blocks/AudioBlockContent/AudioBlockContent.d.ts +3 -3
- package/types/src/blocks/CodeBlockContent/CodeBlockContent.d.ts +46 -34
- package/types/src/blocks/FileBlockContent/FileBlockContent.d.ts +3 -3
- package/types/src/blocks/FileBlockContent/helpers/render/createFileBlockWrapper.d.ts +1 -1
- package/types/src/blocks/HeadingBlockContent/HeadingBlockContent.d.ts +2 -2
- package/types/src/blocks/ImageBlockContent/ImageBlockContent.d.ts +2 -2
- package/types/src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.d.ts +2 -2
- package/types/src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.d.ts +2 -2
- package/types/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.d.ts +2 -2
- package/types/src/blocks/PageBreakBlockContent/PageBreakBlockContent.d.ts +2 -2
- package/types/src/blocks/PageBreakBlockContent/schema.d.ts +13 -13
- package/types/src/blocks/ParagraphBlockContent/ParagraphBlockContent.d.ts +2 -2
- package/types/src/blocks/QuoteBlockContent/QuoteBlockContent.d.ts +52 -0
- package/types/src/blocks/TableBlockContent/TableBlockContent.d.ts +2 -2
- package/types/src/blocks/VideoBlockContent/VideoBlockContent.d.ts +2 -2
- package/types/src/blocks/defaultBlockHelpers.d.ts +2 -2
- package/types/src/blocks/defaultBlocks.d.ts +107 -44
- package/types/src/comments/threadstore/yjs/YjsThreadStore.d.ts +3 -3
- package/types/src/comments/types.d.ts +4 -0
- package/types/src/editor/BlockNoteEditor.d.ts +58 -0
- package/types/src/editor/BlockNoteExtensions.d.ts +3 -2
- package/types/src/editor/BlockNoteTipTapEditor.d.ts +2 -1
- package/types/src/exporter/mapping.d.ts +2 -2
- package/types/src/extensions/BackgroundColor/BackgroundColorMark.d.ts +1 -1
- package/types/src/extensions/Collaboration/createCollaborationExtensions.d.ts +1 -1
- package/types/src/extensions/Comments/CommentsPlugin.d.ts +16 -1
- package/types/src/extensions/HardBreak/HardBreak.d.ts +2 -0
- package/types/src/extensions/TableHandles/TableHandlesPlugin.d.ts +4 -4
- package/types/src/extensions/TextColor/TextColorMark.d.ts +1 -1
- package/types/src/i18n/index.d.ts +2 -0
- package/types/src/i18n/locales/de.d.ts +2 -304
- package/types/src/i18n/locales/en.d.ts +11 -1
- package/types/src/i18n/locales/es.d.ts +2 -269
- package/types/src/i18n/locales/hr.d.ts +2 -266
- package/types/src/i18n/locales/it.d.ts +2 -269
- package/types/src/index.d.ts +1 -2
- package/types/src/locales.d.ts +1 -0
- package/types/src/pm-nodes/BlockContainer.d.ts +2 -7
- package/types/src/pm-nodes/BlockGroup.d.ts +2 -7
- package/types/src/schema/blocks/types.d.ts +1 -0
- package/types/src/schema/inlineContent/internal.d.ts +1 -1
- package/README.md +0 -125
- package/src/blocks/CodeBlockContent/defaultSupportedLanguages.ts +0 -116
- package/types/src/blocks/CodeBlockContent/shiki.bundle.d.ts +0 -82
|
@@ -2,28 +2,65 @@ import { InputRule, isTextSelection } from "@tiptap/core";
|
|
|
2
2
|
import { TextSelection } from "@tiptap/pm/state";
|
|
3
3
|
import { createHighlightPlugin, Parser } from "prosemirror-highlight";
|
|
4
4
|
import { createParser } from "prosemirror-highlight/shiki";
|
|
5
|
-
import {
|
|
6
|
-
BundledLanguage,
|
|
7
|
-
bundledLanguagesInfo,
|
|
8
|
-
createHighlighter,
|
|
9
|
-
Highlighter,
|
|
10
|
-
} from "shiki";
|
|
11
5
|
import {
|
|
12
6
|
createBlockSpecFromStronglyTypedTiptapNode,
|
|
13
7
|
createStronglyTypedTiptapNode,
|
|
14
8
|
PropSchema,
|
|
15
9
|
} from "../../schema/index.js";
|
|
16
10
|
import { createDefaultBlockDOMOutputSpec } from "../defaultBlockHelpers.js";
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
11
|
+
import type { HighlighterGeneric } from "@shikijs/types";
|
|
12
|
+
import { BlockNoteEditor } from "../../index.js";
|
|
13
|
+
|
|
14
|
+
export type CodeBlockOptions = {
|
|
15
|
+
/**
|
|
16
|
+
* Whether to indent lines with a tab when the user presses `Tab` in a code block.
|
|
17
|
+
*
|
|
18
|
+
* @default true
|
|
19
|
+
*/
|
|
20
|
+
indentLineWithTab?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* The default language to use for code blocks.
|
|
23
|
+
*
|
|
24
|
+
* @default "text"
|
|
25
|
+
*/
|
|
26
|
+
defaultLanguage?: string;
|
|
27
|
+
/**
|
|
28
|
+
* The languages that are supported in the editor.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* {
|
|
32
|
+
* javascript: {
|
|
33
|
+
* name: "JavaScript",
|
|
34
|
+
* aliases: ["js"],
|
|
35
|
+
* },
|
|
36
|
+
* typescript: {
|
|
37
|
+
* name: "TypeScript",
|
|
38
|
+
* aliases: ["ts"],
|
|
39
|
+
* },
|
|
40
|
+
* }
|
|
41
|
+
*/
|
|
42
|
+
supportedLanguages: Record<
|
|
43
|
+
string,
|
|
44
|
+
{
|
|
45
|
+
/**
|
|
46
|
+
* The display name of the language.
|
|
47
|
+
*/
|
|
48
|
+
name: string;
|
|
49
|
+
/**
|
|
50
|
+
* Aliases for this language.
|
|
51
|
+
*/
|
|
52
|
+
aliases?: string[];
|
|
53
|
+
}
|
|
54
|
+
>;
|
|
55
|
+
/**
|
|
56
|
+
* The highlighter to use for code blocks.
|
|
57
|
+
*/
|
|
58
|
+
createHighlighter?: () => Promise<HighlighterGeneric<any, any>>;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
type CodeBlockConfigOptions = {
|
|
62
|
+
editor: BlockNoteEditor<any, any, any>;
|
|
63
|
+
};
|
|
27
64
|
|
|
28
65
|
export const shikiParserSymbol = Symbol.for("blocknote.shikiParser");
|
|
29
66
|
export const shikiHighlighterPromiseSymbol = Symbol.for(
|
|
@@ -31,8 +68,7 @@ export const shikiHighlighterPromiseSymbol = Symbol.for(
|
|
|
31
68
|
);
|
|
32
69
|
export const defaultCodeBlockPropSchema = {
|
|
33
70
|
language: {
|
|
34
|
-
default: "
|
|
35
|
-
values: [...defaultSupportedLanguages.map((lang) => lang.id)],
|
|
71
|
+
default: "text",
|
|
36
72
|
},
|
|
37
73
|
} satisfies PropSchema;
|
|
38
74
|
|
|
@@ -45,18 +81,17 @@ const CodeBlockContent = createStronglyTypedTiptapNode({
|
|
|
45
81
|
defining: true,
|
|
46
82
|
addOptions() {
|
|
47
83
|
return {
|
|
48
|
-
defaultLanguage: "
|
|
84
|
+
defaultLanguage: "text",
|
|
49
85
|
indentLineWithTab: true,
|
|
50
|
-
supportedLanguages:
|
|
86
|
+
supportedLanguages: {},
|
|
51
87
|
};
|
|
52
88
|
},
|
|
53
89
|
addAttributes() {
|
|
54
|
-
const
|
|
55
|
-
.supportedLanguages as SupportedLanguageConfig[];
|
|
90
|
+
const options = this.options as CodeBlockConfigOptions;
|
|
56
91
|
|
|
57
92
|
return {
|
|
58
93
|
language: {
|
|
59
|
-
default:
|
|
94
|
+
default: options.editor.settings.codeBlock.defaultLanguage,
|
|
60
95
|
parseHTML: (inputElement) => {
|
|
61
96
|
let element = inputElement as HTMLElement | null;
|
|
62
97
|
let language: string | null = null;
|
|
@@ -91,17 +126,13 @@ const CodeBlockContent = createStronglyTypedTiptapNode({
|
|
|
91
126
|
return null;
|
|
92
127
|
}
|
|
93
128
|
|
|
94
|
-
return (
|
|
95
|
-
supportedLanguages.find(({ match }) => {
|
|
96
|
-
return match.includes(language);
|
|
97
|
-
})?.id || this.options.defaultLanguage
|
|
98
|
-
);
|
|
129
|
+
return getLanguageId(options.editor.settings.codeBlock, language);
|
|
99
130
|
},
|
|
100
131
|
renderHTML: (attributes) => {
|
|
101
|
-
|
|
102
|
-
return attributes.language && attributes.language !== "text"
|
|
132
|
+
return attributes.language
|
|
103
133
|
? {
|
|
104
134
|
class: `language-${attributes.language}`,
|
|
135
|
+
"data-language": attributes.language,
|
|
105
136
|
}
|
|
106
137
|
: {};
|
|
107
138
|
},
|
|
@@ -143,8 +174,7 @@ const CodeBlockContent = createStronglyTypedTiptapNode({
|
|
|
143
174
|
};
|
|
144
175
|
},
|
|
145
176
|
addNodeView() {
|
|
146
|
-
const
|
|
147
|
-
.supportedLanguages as SupportedLanguageConfig[];
|
|
177
|
+
const options = this.options as CodeBlockConfigOptions;
|
|
148
178
|
|
|
149
179
|
return ({ editor, node, getPos, HTMLAttributes }) => {
|
|
150
180
|
const pre = document.createElement("pre");
|
|
@@ -169,7 +199,9 @@ const CodeBlockContent = createStronglyTypedTiptapNode({
|
|
|
169
199
|
});
|
|
170
200
|
};
|
|
171
201
|
|
|
172
|
-
|
|
202
|
+
Object.entries(
|
|
203
|
+
options.editor.settings.codeBlock.supportedLanguages
|
|
204
|
+
).forEach(([id, { name }]) => {
|
|
173
205
|
const option = document.createElement("option");
|
|
174
206
|
|
|
175
207
|
option.value = id;
|
|
@@ -178,7 +210,9 @@ const CodeBlockContent = createStronglyTypedTiptapNode({
|
|
|
178
210
|
});
|
|
179
211
|
|
|
180
212
|
selectWrapper.contentEditable = "false";
|
|
181
|
-
select.value =
|
|
213
|
+
select.value =
|
|
214
|
+
node.attrs.language ||
|
|
215
|
+
options.editor.settings.codeBlock.defaultLanguage;
|
|
182
216
|
dom.removeChild(contentDOM);
|
|
183
217
|
dom.appendChild(selectWrapper);
|
|
184
218
|
dom.appendChild(pre);
|
|
@@ -203,24 +237,30 @@ const CodeBlockContent = createStronglyTypedTiptapNode({
|
|
|
203
237
|
};
|
|
204
238
|
},
|
|
205
239
|
addProseMirrorPlugins() {
|
|
206
|
-
const
|
|
207
|
-
.supportedLanguages as SupportedLanguageConfig[];
|
|
240
|
+
const options = this.options as CodeBlockConfigOptions;
|
|
208
241
|
const globalThisForShiki = globalThis as {
|
|
209
|
-
[shikiHighlighterPromiseSymbol]?: Promise<
|
|
242
|
+
[shikiHighlighterPromiseSymbol]?: Promise<HighlighterGeneric<any, any>>;
|
|
210
243
|
[shikiParserSymbol]?: Parser;
|
|
211
244
|
};
|
|
212
245
|
|
|
213
|
-
let highlighter:
|
|
246
|
+
let highlighter: HighlighterGeneric<any, any> | undefined;
|
|
214
247
|
let parser: Parser | undefined;
|
|
215
|
-
|
|
216
|
-
const lazyParser: Parser = (
|
|
248
|
+
let hasWarned = false;
|
|
249
|
+
const lazyParser: Parser = (parserOptions) => {
|
|
250
|
+
if (!options.editor.settings.codeBlock.createHighlighter) {
|
|
251
|
+
if (process.env.NODE_ENV === "development" && !hasWarned) {
|
|
252
|
+
// eslint-disable-next-line no-console
|
|
253
|
+
console.log(
|
|
254
|
+
"For syntax highlighting of code blocks, you must provide a highlighter function"
|
|
255
|
+
);
|
|
256
|
+
hasWarned = true;
|
|
257
|
+
}
|
|
258
|
+
return [];
|
|
259
|
+
}
|
|
217
260
|
if (!highlighter) {
|
|
218
261
|
globalThisForShiki[shikiHighlighterPromiseSymbol] =
|
|
219
262
|
globalThisForShiki[shikiHighlighterPromiseSymbol] ||
|
|
220
|
-
createHighlighter(
|
|
221
|
-
themes: ["github-dark"],
|
|
222
|
-
langs: [],
|
|
223
|
-
});
|
|
263
|
+
options.editor.settings.codeBlock.createHighlighter();
|
|
224
264
|
|
|
225
265
|
return globalThisForShiki[shikiHighlighterPromiseSymbol].then(
|
|
226
266
|
(createdHighlighter) => {
|
|
@@ -229,25 +269,25 @@ const CodeBlockContent = createStronglyTypedTiptapNode({
|
|
|
229
269
|
);
|
|
230
270
|
}
|
|
231
271
|
|
|
232
|
-
const language =
|
|
272
|
+
const language = parserOptions.language;
|
|
233
273
|
|
|
234
274
|
if (
|
|
235
275
|
language &&
|
|
236
276
|
language !== "text" &&
|
|
237
277
|
!highlighter.getLoadedLanguages().includes(language) &&
|
|
238
|
-
|
|
239
|
-
bundledLanguagesInfo.find(({ id }) => id === language)
|
|
278
|
+
language in options.editor.settings.codeBlock.supportedLanguages
|
|
240
279
|
) {
|
|
241
|
-
return highlighter.loadLanguage(language
|
|
280
|
+
return highlighter.loadLanguage(language);
|
|
242
281
|
}
|
|
243
282
|
|
|
244
283
|
if (!parser) {
|
|
245
284
|
parser =
|
|
246
|
-
globalThisForShiki[shikiParserSymbol] ||
|
|
285
|
+
globalThisForShiki[shikiParserSymbol] ||
|
|
286
|
+
createParser(highlighter as any);
|
|
247
287
|
globalThisForShiki[shikiParserSymbol] = parser;
|
|
248
288
|
}
|
|
249
289
|
|
|
250
|
-
return parser(
|
|
290
|
+
return parser(parserOptions);
|
|
251
291
|
};
|
|
252
292
|
|
|
253
293
|
const shikiLazyPlugin = createHighlightPlugin({
|
|
@@ -259,8 +299,7 @@ const CodeBlockContent = createStronglyTypedTiptapNode({
|
|
|
259
299
|
return [shikiLazyPlugin];
|
|
260
300
|
},
|
|
261
301
|
addInputRules() {
|
|
262
|
-
const
|
|
263
|
-
.supportedLanguages as SupportedLanguageConfig[];
|
|
302
|
+
const options = this.options as CodeBlockConfigOptions;
|
|
264
303
|
|
|
265
304
|
return [
|
|
266
305
|
new InputRule({
|
|
@@ -269,10 +308,10 @@ const CodeBlockContent = createStronglyTypedTiptapNode({
|
|
|
269
308
|
const $start = state.doc.resolve(range.from);
|
|
270
309
|
const languageName = match[1].trim();
|
|
271
310
|
const attributes = {
|
|
272
|
-
language:
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
311
|
+
language: getLanguageId(
|
|
312
|
+
options.editor.settings.codeBlock,
|
|
313
|
+
languageName
|
|
314
|
+
),
|
|
276
315
|
};
|
|
277
316
|
|
|
278
317
|
if (
|
|
@@ -383,18 +422,10 @@ export const CodeBlock = createBlockSpecFromStronglyTypedTiptapNode(
|
|
|
383
422
|
defaultCodeBlockPropSchema
|
|
384
423
|
);
|
|
385
424
|
|
|
386
|
-
|
|
387
|
-
return
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
default:
|
|
392
|
-
options.defaultLanguage ||
|
|
393
|
-
defaultCodeBlockPropSchema.language.default,
|
|
394
|
-
values:
|
|
395
|
-
options.supportedLanguages?.map((lang) => lang.id) ||
|
|
396
|
-
defaultCodeBlockPropSchema.language.values,
|
|
397
|
-
},
|
|
398
|
-
}
|
|
425
|
+
function getLanguageId(options: CodeBlockOptions, languageName: string) {
|
|
426
|
+
return (
|
|
427
|
+
Object.entries(options.supportedLanguages).find(([id, { aliases }]) => {
|
|
428
|
+
return aliases?.includes(languageName) || id === languageName;
|
|
429
|
+
})?.[0] || languageName
|
|
399
430
|
);
|
|
400
431
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createBlockSpecFromStronglyTypedTiptapNode,
|
|
3
|
+
createStronglyTypedTiptapNode,
|
|
4
|
+
} from "../../schema/index.js";
|
|
5
|
+
import { createDefaultBlockDOMOutputSpec } from "../defaultBlockHelpers.js";
|
|
6
|
+
import { defaultProps } from "../defaultProps.js";
|
|
7
|
+
import { getBlockInfoFromSelection } from "../../api/getBlockInfoFromPos.js";
|
|
8
|
+
import { updateBlockCommand } from "../../api/blockManipulation/commands/updateBlock/updateBlock.js";
|
|
9
|
+
import { InputRule } from "@tiptap/core";
|
|
10
|
+
|
|
11
|
+
export const quotePropSchema = {
|
|
12
|
+
...defaultProps,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const QuoteBlockContent = createStronglyTypedTiptapNode({
|
|
16
|
+
name: "quote",
|
|
17
|
+
content: "inline*",
|
|
18
|
+
group: "blockContent",
|
|
19
|
+
|
|
20
|
+
addInputRules() {
|
|
21
|
+
return [
|
|
22
|
+
// Creates a block quote when starting with ">".
|
|
23
|
+
new InputRule({
|
|
24
|
+
find: new RegExp(`^>\\s$`),
|
|
25
|
+
handler: ({ state, chain, range }) => {
|
|
26
|
+
const blockInfo = getBlockInfoFromSelection(state);
|
|
27
|
+
if (
|
|
28
|
+
!blockInfo.isBlockContainer ||
|
|
29
|
+
blockInfo.blockContent.node.type.spec.content !== "inline*"
|
|
30
|
+
) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
chain()
|
|
35
|
+
.command(
|
|
36
|
+
updateBlockCommand(
|
|
37
|
+
this.options.editor,
|
|
38
|
+
blockInfo.bnBlock.beforePos,
|
|
39
|
+
{
|
|
40
|
+
type: "quote",
|
|
41
|
+
props: {},
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
)
|
|
45
|
+
// Removes the ">" character used to set the list.
|
|
46
|
+
.deleteRange({ from: range.from, to: range.to });
|
|
47
|
+
},
|
|
48
|
+
}),
|
|
49
|
+
];
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
addKeyboardShortcuts() {
|
|
53
|
+
return {
|
|
54
|
+
"Mod-Alt-q": () => {
|
|
55
|
+
const blockInfo = getBlockInfoFromSelection(this.editor.state);
|
|
56
|
+
if (
|
|
57
|
+
!blockInfo.isBlockContainer ||
|
|
58
|
+
blockInfo.blockContent.node.type.spec.content !== "inline*"
|
|
59
|
+
) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return this.editor.commands.command(
|
|
64
|
+
updateBlockCommand(this.options.editor, blockInfo.bnBlock.beforePos, {
|
|
65
|
+
type: "quote",
|
|
66
|
+
})
|
|
67
|
+
);
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
parseHTML() {
|
|
73
|
+
return [
|
|
74
|
+
{ tag: "div[data-content-type=" + this.name + "]" },
|
|
75
|
+
{
|
|
76
|
+
tag: "blockquote",
|
|
77
|
+
node: "quote",
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
renderHTML({ HTMLAttributes }) {
|
|
83
|
+
return createDefaultBlockDOMOutputSpec(
|
|
84
|
+
this.name,
|
|
85
|
+
"blockquote",
|
|
86
|
+
{
|
|
87
|
+
...(this.options.domAttributes?.blockContent || {}),
|
|
88
|
+
...HTMLAttributes,
|
|
89
|
+
},
|
|
90
|
+
this.options.domAttributes?.inlineContent || {}
|
|
91
|
+
);
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
export const Quote = createBlockSpecFromStronglyTypedTiptapNode(
|
|
96
|
+
QuoteBlockContent,
|
|
97
|
+
quotePropSchema
|
|
98
|
+
);
|
|
@@ -29,14 +29,14 @@ import { BulletListItem } from "./ListItemBlockContent/BulletListItemBlockConten
|
|
|
29
29
|
import { CheckListItem } from "./ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.js";
|
|
30
30
|
import { NumberedListItem } from "./ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.js";
|
|
31
31
|
import { Paragraph } from "./ParagraphBlockContent/ParagraphBlockContent.js";
|
|
32
|
+
import { Quote } from "./QuoteBlockContent/QuoteBlockContent.js";
|
|
32
33
|
import { Table } from "./TableBlockContent/TableBlockContent.js";
|
|
33
34
|
import { VideoBlock } from "./VideoBlockContent/VideoBlockContent.js";
|
|
34
35
|
|
|
35
|
-
export { customizeCodeBlock } from "./CodeBlockContent/CodeBlockContent.js";
|
|
36
|
-
|
|
37
36
|
export const defaultBlockSpecs = {
|
|
38
37
|
paragraph: Paragraph,
|
|
39
38
|
heading: Heading,
|
|
39
|
+
quote: Quote,
|
|
40
40
|
codeBlock: CodeBlock,
|
|
41
41
|
bulletListItem: BulletListItem,
|
|
42
42
|
numberedListItem: NumberedListItem,
|
|
@@ -237,6 +237,7 @@ export class YjsThreadStore extends YjsThreadStoreBase {
|
|
|
237
237
|
|
|
238
238
|
yThread.set("resolved", true);
|
|
239
239
|
yThread.set("resolvedUpdatedAt", new Date().getTime());
|
|
240
|
+
yThread.set("resolvedBy", this.userId);
|
|
240
241
|
});
|
|
241
242
|
|
|
242
243
|
public unresolveThread = this.transact((options: { threadId: string }) => {
|
|
@@ -40,6 +40,7 @@ export function threadToYMap(thread: ThreadData) {
|
|
|
40
40
|
yMap.set("comments", commentsArray);
|
|
41
41
|
yMap.set("resolved", thread.resolved);
|
|
42
42
|
yMap.set("resolvedUpdatedAt", thread.resolvedUpdatedAt?.getTime());
|
|
43
|
+
yMap.set("resolvedBy", thread.resolvedBy);
|
|
43
44
|
yMap.set("metadata", thread.metadata);
|
|
44
45
|
return yMap;
|
|
45
46
|
}
|
|
@@ -115,7 +116,8 @@ export function yMapToThread(yMap: Y.Map<any>): ThreadData {
|
|
|
115
116
|
(comment) => yMapToComment(comment)
|
|
116
117
|
),
|
|
117
118
|
resolved: yMap.get("resolved"),
|
|
118
|
-
resolvedUpdatedAt: yMap.get("resolvedUpdatedAt"),
|
|
119
|
+
resolvedUpdatedAt: new Date(yMap.get("resolvedUpdatedAt")),
|
|
120
|
+
resolvedBy: yMap.get("resolvedBy"),
|
|
119
121
|
metadata: yMap.get("metadata"),
|
|
120
122
|
};
|
|
121
123
|
}
|
package/src/comments/types.ts
CHANGED
|
@@ -105,6 +105,10 @@ export type ThreadData = {
|
|
|
105
105
|
* The date when the thread was marked as resolved.
|
|
106
106
|
*/
|
|
107
107
|
resolvedUpdatedAt?: Date;
|
|
108
|
+
/**
|
|
109
|
+
* The id of the user that marked the thread as resolved.
|
|
110
|
+
*/
|
|
111
|
+
resolvedBy?: string;
|
|
108
112
|
/**
|
|
109
113
|
* You can use this store any additional information about the thread.
|
|
110
114
|
*/
|
package/src/editor/Block.css
CHANGED
|
@@ -37,6 +37,10 @@ BASIC STYLES
|
|
|
37
37
|
outline: 4px solid rgb(100, 160, 255);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
.bn-inline-content {
|
|
41
|
+
width: 100%;
|
|
42
|
+
}
|
|
43
|
+
|
|
40
44
|
/*
|
|
41
45
|
NESTED BLOCKS
|
|
42
46
|
*/
|
|
@@ -146,6 +150,14 @@ NESTED BLOCKS
|
|
|
146
150
|
font-weight: bold;
|
|
147
151
|
}
|
|
148
152
|
|
|
153
|
+
/* QUOTES */
|
|
154
|
+
[data-content-type="quote"] blockquote {
|
|
155
|
+
border-left: 2px solid rgb(125, 121, 122);
|
|
156
|
+
color: rgb(125, 121, 122);
|
|
157
|
+
margin: 0;
|
|
158
|
+
padding-left: 1em;
|
|
159
|
+
}
|
|
160
|
+
|
|
149
161
|
/* LISTS */
|
|
150
162
|
|
|
151
163
|
.bn-block-content::before {
|
|
@@ -188,6 +200,7 @@ NESTED BLOCKS
|
|
|
188
200
|
/* Checked */
|
|
189
201
|
.bn-block-content[data-content-type="checkListItem"] > div {
|
|
190
202
|
display: flex;
|
|
203
|
+
width: 100%;
|
|
191
204
|
}
|
|
192
205
|
|
|
193
206
|
.bn-block-content[data-content-type="checkListItem"] > div > div > input {
|
|
@@ -542,6 +555,6 @@ NESTED BLOCKS
|
|
|
542
555
|
background: rgba(255, 200, 0, 0.15);
|
|
543
556
|
}
|
|
544
557
|
|
|
545
|
-
.bn-thread-mark
|
|
558
|
+
.bn-thread-mark .bn-thread-mark-selected {
|
|
546
559
|
background: rgba(255, 200, 0, 0.25);
|
|
547
560
|
}
|
|
@@ -43,7 +43,10 @@ import {
|
|
|
43
43
|
import { createExternalHTMLExporter } from "../api/exporters/html/externalHTMLExporter.js";
|
|
44
44
|
import { blocksToMarkdown } from "../api/exporters/markdown/markdownExporter.js";
|
|
45
45
|
import { HTMLToBlocks } from "../api/parsers/html/parseHTML.js";
|
|
46
|
-
import {
|
|
46
|
+
import {
|
|
47
|
+
markdownToBlocks,
|
|
48
|
+
markdownToHTML,
|
|
49
|
+
} from "../api/parsers/markdown/parseMarkdown.js";
|
|
47
50
|
import {
|
|
48
51
|
Block,
|
|
49
52
|
DefaultBlockSchema,
|
|
@@ -91,7 +94,7 @@ import {
|
|
|
91
94
|
import { Dictionary } from "../i18n/dictionary.js";
|
|
92
95
|
import { en } from "../i18n/locales/index.js";
|
|
93
96
|
|
|
94
|
-
import { Plugin, Transaction } from "@tiptap/pm/state";
|
|
97
|
+
import { Plugin, TextSelection, Transaction } from "@tiptap/pm/state";
|
|
95
98
|
import { dropCursor } from "prosemirror-dropcursor";
|
|
96
99
|
import { EditorView } from "prosemirror-view";
|
|
97
100
|
import { ySyncPluginKey } from "y-prosemirror";
|
|
@@ -101,6 +104,8 @@ import { nodeToBlock } from "../api/nodeConversions/nodeToBlock.js";
|
|
|
101
104
|
import type { ThreadStore, User } from "../comments/index.js";
|
|
102
105
|
import "../style.css";
|
|
103
106
|
import { EventEmitter } from "../util/EventEmitter.js";
|
|
107
|
+
import { CodeBlockOptions } from "../blocks/CodeBlockContent/CodeBlockContent.js";
|
|
108
|
+
import { nestedListsToBlockNoteStructure } from "../api/parsers/html/util/nestedLists.js";
|
|
104
109
|
|
|
105
110
|
export type BlockNoteExtensionFactory = (
|
|
106
111
|
editor: BlockNoteEditor<any, any, any>
|
|
@@ -156,6 +161,11 @@ export type BlockNoteEditorOptions<
|
|
|
156
161
|
showCursorLabels?: "always" | "activity";
|
|
157
162
|
};
|
|
158
163
|
|
|
164
|
+
/**
|
|
165
|
+
* Options for code blocks.
|
|
166
|
+
*/
|
|
167
|
+
codeBlock?: CodeBlockOptions;
|
|
168
|
+
|
|
159
169
|
comments: {
|
|
160
170
|
threadStore: ThreadStore;
|
|
161
171
|
};
|
|
@@ -212,6 +222,39 @@ export type BlockNoteEditorOptions<
|
|
|
212
222
|
string | undefined
|
|
213
223
|
>;
|
|
214
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Custom paste handler that can be used to override the default paste behavior.
|
|
227
|
+
* @returns The function should return `true` if the paste event was handled, otherwise it should return `false` if it should be canceled or `undefined` if it should be handled by another handler.
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* ```ts
|
|
231
|
+
* pasteHandler: ({ defaultPasteHandler }) => {
|
|
232
|
+
* return defaultPasteHandler({ pasteBehavior: "prefer-html" });
|
|
233
|
+
* }
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
pasteHandler?: (context: {
|
|
237
|
+
event: ClipboardEvent;
|
|
238
|
+
editor: BlockNoteEditor<BSchema, ISchema, SSchema>;
|
|
239
|
+
/**
|
|
240
|
+
* The default paste handler
|
|
241
|
+
* @param context The context object
|
|
242
|
+
* @returns Whether the paste event was handled or not
|
|
243
|
+
*/
|
|
244
|
+
defaultPasteHandler: (context?: {
|
|
245
|
+
/**
|
|
246
|
+
* Whether to prioritize Markdown content in `text/plain` over `text/html` when pasting from the clipboard.
|
|
247
|
+
* @default true
|
|
248
|
+
*/
|
|
249
|
+
prioritizeMarkdownOverHTML?: boolean;
|
|
250
|
+
/**
|
|
251
|
+
* Whether to parse `text/plain` content from the clipboard as Markdown content.
|
|
252
|
+
* @default true
|
|
253
|
+
*/
|
|
254
|
+
plainTextAsMarkdown?: boolean;
|
|
255
|
+
}) => boolean | undefined;
|
|
256
|
+
}) => boolean | undefined;
|
|
257
|
+
|
|
215
258
|
/**
|
|
216
259
|
* Resolve a URL of a file block to one that can be displayed or downloaded. This can be used for creating authenticated URL or
|
|
217
260
|
* implementing custom protocols / schemes
|
|
@@ -442,6 +485,7 @@ export class BlockNoteEditor<
|
|
|
442
485
|
cellTextColor: boolean;
|
|
443
486
|
headers: boolean;
|
|
444
487
|
};
|
|
488
|
+
codeBlock: CodeBlockOptions;
|
|
445
489
|
};
|
|
446
490
|
|
|
447
491
|
public static create<
|
|
@@ -489,6 +533,12 @@ export class BlockNoteEditor<
|
|
|
489
533
|
cellTextColor: options?.tables?.cellTextColor ?? false,
|
|
490
534
|
headers: options?.tables?.headers ?? false,
|
|
491
535
|
},
|
|
536
|
+
codeBlock: {
|
|
537
|
+
indentLineWithTab: options?.codeBlock?.indentLineWithTab ?? true,
|
|
538
|
+
defaultLanguage: options?.codeBlock?.defaultLanguage ?? "text",
|
|
539
|
+
supportedLanguages: options?.codeBlock?.supportedLanguages ?? {},
|
|
540
|
+
createHighlighter: options?.codeBlock?.createHighlighter ?? undefined,
|
|
541
|
+
},
|
|
492
542
|
};
|
|
493
543
|
|
|
494
544
|
// apply defaults
|
|
@@ -532,6 +582,7 @@ export class BlockNoteEditor<
|
|
|
532
582
|
tabBehavior: newOptions.tabBehavior,
|
|
533
583
|
sideMenuDetection: newOptions.sideMenuDetection || "viewport",
|
|
534
584
|
comments: newOptions.comments,
|
|
585
|
+
pasteHandler: newOptions.pasteHandler,
|
|
535
586
|
});
|
|
536
587
|
|
|
537
588
|
// add extensions from _tiptapOptions
|
|
@@ -688,7 +739,7 @@ export class BlockNoteEditor<
|
|
|
688
739
|
parentElement?: HTMLElement | null,
|
|
689
740
|
contentComponent?: any
|
|
690
741
|
) => {
|
|
691
|
-
this._tiptapEditor.mount(parentElement, contentComponent);
|
|
742
|
+
this._tiptapEditor.mount(this, parentElement, contentComponent);
|
|
692
743
|
};
|
|
693
744
|
|
|
694
745
|
/**
|
|
@@ -1136,17 +1187,18 @@ export class BlockNoteEditor<
|
|
|
1136
1187
|
}
|
|
1137
1188
|
|
|
1138
1189
|
const { from, to } = this._tiptapEditor.state.selection;
|
|
1139
|
-
|
|
1140
|
-
if (!text) {
|
|
1141
|
-
text = this._tiptapEditor.state.doc.textBetween(from, to);
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
1190
|
const mark = this.pmSchema.mark("link", { href: url });
|
|
1145
1191
|
|
|
1146
1192
|
this.dispatch(
|
|
1147
|
-
|
|
1148
|
-
.
|
|
1149
|
-
|
|
1193
|
+
text
|
|
1194
|
+
? this._tiptapEditor.state.tr
|
|
1195
|
+
.insertText(text, from, to)
|
|
1196
|
+
.addMark(from, from + text.length, mark)
|
|
1197
|
+
: this._tiptapEditor.state.tr
|
|
1198
|
+
.setSelection(
|
|
1199
|
+
TextSelection.create(this._tiptapEditor.state.tr.doc, to)
|
|
1200
|
+
)
|
|
1201
|
+
.addMark(from, to, mark)
|
|
1150
1202
|
);
|
|
1151
1203
|
}
|
|
1152
1204
|
|
|
@@ -1431,4 +1483,44 @@ export class BlockNoteEditor<
|
|
|
1431
1483
|
public setForceSelectionVisible(forceSelectionVisible: boolean) {
|
|
1432
1484
|
this.showSelectionPlugin.setEnabled(forceSelectionVisible);
|
|
1433
1485
|
}
|
|
1486
|
+
|
|
1487
|
+
/**
|
|
1488
|
+
* This will convert HTML into a format that is compatible with BlockNote.
|
|
1489
|
+
*/
|
|
1490
|
+
private convertHtmlToBlockNoteHtml(html: string) {
|
|
1491
|
+
const htmlNode = nestedListsToBlockNoteStructure(html.trim());
|
|
1492
|
+
return htmlNode.innerHTML;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
/**
|
|
1496
|
+
* Paste HTML into the editor. Defaults to converting HTML to BlockNote HTML.
|
|
1497
|
+
* @param html The HTML to paste.
|
|
1498
|
+
* @param raw Whether to paste the HTML as is, or to convert it to BlockNote HTML.
|
|
1499
|
+
*/
|
|
1500
|
+
public pasteHTML(html: string, raw = false) {
|
|
1501
|
+
let htmlToPaste = html;
|
|
1502
|
+
if (!raw) {
|
|
1503
|
+
htmlToPaste = this.convertHtmlToBlockNoteHtml(html);
|
|
1504
|
+
}
|
|
1505
|
+
if (!htmlToPaste) {
|
|
1506
|
+
return;
|
|
1507
|
+
}
|
|
1508
|
+
this.prosemirrorView?.pasteHTML(htmlToPaste);
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
/**
|
|
1512
|
+
* Paste text into the editor. Defaults to interpreting text as markdown.
|
|
1513
|
+
* @param text The text to paste.
|
|
1514
|
+
*/
|
|
1515
|
+
public pasteText(text: string) {
|
|
1516
|
+
return this.prosemirrorView?.pasteText(text);
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
/**
|
|
1520
|
+
* Paste markdown into the editor.
|
|
1521
|
+
* @param markdown The markdown to paste.
|
|
1522
|
+
*/
|
|
1523
|
+
public async pasteMarkdown(markdown: string) {
|
|
1524
|
+
return this.pasteHTML(await markdownToHTML(markdown));
|
|
1525
|
+
}
|
|
1434
1526
|
}
|