@blocknote/core 0.32.0 → 0.34.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 +8 -8
- package/dist/blocknote.cjs.map +1 -1
- package/dist/blocknote.js +1816 -1665
- package/dist/blocknote.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/webpack-stats.json +1 -1
- package/package.json +2 -2
- package/src/api/__snapshots__/blocks-indented-changed.json +129 -0
- package/src/api/__snapshots__/blocks-moved-deeper-into-nesting.json +164 -0
- package/src/api/__snapshots__/blocks-moved-multiple-in-same-transaction.json +188 -0
- package/src/api/__snapshots__/blocks-moved-to-different-parent.json +78 -0
- package/src/api/__snapshots__/blocks-moved-to-root-level.json +78 -0
- package/src/api/__snapshots__/blocks-outdented-changed.json +129 -0
- package/src/api/blockManipulation/commands/nestBlock/nestBlock.ts +58 -59
- package/src/api/nodeUtil.test.ts +228 -1
- package/src/api/nodeUtil.ts +135 -118
- package/src/api/parsers/markdown/detectMarkdown.test.ts +211 -0
- package/src/api/parsers/markdown/detectMarkdown.ts +3 -2
- package/src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts +2 -1
- package/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts +2 -1
- package/src/blocks/ToggleWrapper/createToggleWrapper.ts +2 -0
- package/src/blocks/defaultBlockTypeGuards.ts +30 -0
- package/src/editor/BlockNoteEditor.ts +27 -10
- package/src/editor/BlockNoteExtensions.ts +3 -5
- package/src/exporter/Exporter.ts +2 -0
- package/src/exporter/mapping.ts +1 -0
- package/src/extensions/BlockChange/BlockChangePlugin.ts +66 -0
- package/src/extensions/Collaboration/CursorPlugin.ts +33 -2
- package/src/extensions/SideMenu/SideMenuPlugin.ts +290 -207
- package/src/extensions/SuggestionMenu/SuggestionPlugin.ts +22 -12
- package/src/schema/inlineContent/types.ts +8 -0
- package/src/util/browser.ts +11 -1
- package/types/src/api/nodeUtil.d.ts +15 -21
- package/types/src/api/parsers/markdown/detectMarkdown.test.d.ts +1 -0
- package/types/src/blocks/defaultBlockTypeGuards.d.ts +7 -1
- package/types/src/editor/BlockNoteEditor.d.ts +11 -8
- package/types/src/editor/BlockNoteExtensions.d.ts +0 -1
- package/types/src/exporter/Exporter.d.ts +1 -1
- package/types/src/exporter/mapping.d.ts +1 -1
- package/types/src/extensions/BlockChange/BlockChangePlugin.d.ts +15 -0
- package/types/src/extensions/Collaboration/CursorPlugin.d.ts +6 -0
- package/types/src/extensions/SideMenu/SideMenuPlugin.d.ts +50 -9
- package/types/src/schema/inlineContent/types.d.ts +4 -0
|
@@ -120,6 +120,7 @@ import { EventEmitter } from "../util/EventEmitter.js";
|
|
|
120
120
|
import { BlockNoteExtension } from "./BlockNoteExtension.js";
|
|
121
121
|
|
|
122
122
|
import "../style.css";
|
|
123
|
+
import { BlockChangePlugin } from "../extensions/BlockChange/BlockChangePlugin.js";
|
|
123
124
|
|
|
124
125
|
/**
|
|
125
126
|
* A factory function that returns a BlockNoteExtension
|
|
@@ -312,15 +313,6 @@ export type BlockNoteEditorOptions<
|
|
|
312
313
|
*/
|
|
313
314
|
setIdAttribute?: boolean;
|
|
314
315
|
|
|
315
|
-
/**
|
|
316
|
-
* The detection mode for showing the side menu - "viewport" always shows the
|
|
317
|
-
* side menu for the block next to the mouse cursor, while "editor" only shows
|
|
318
|
-
* it when hovering the editor or the side menu itself.
|
|
319
|
-
*
|
|
320
|
-
* @default "viewport"
|
|
321
|
-
*/
|
|
322
|
-
sideMenuDetection: "viewport" | "editor";
|
|
323
|
-
|
|
324
316
|
/**
|
|
325
317
|
Select desired behavior when pressing `Tab` (or `Shift-Tab`). Specifically,
|
|
326
318
|
what should happen when a user has selected multiple blocks while a toolbar
|
|
@@ -639,7 +631,6 @@ export class BlockNoteEditor<
|
|
|
639
631
|
dropCursor: this.options.dropCursor ?? dropCursor,
|
|
640
632
|
placeholders: newOptions.placeholders,
|
|
641
633
|
tabBehavior: newOptions.tabBehavior,
|
|
642
|
-
sideMenuDetection: newOptions.sideMenuDetection || "viewport",
|
|
643
634
|
comments: newOptions.comments,
|
|
644
635
|
pasteHandler: newOptions.pasteHandler,
|
|
645
636
|
});
|
|
@@ -1606,6 +1597,32 @@ export class BlockNoteEditor<
|
|
|
1606
1597
|
(this.extensions["yCursorPlugin"] as CursorPlugin).updateUser(user);
|
|
1607
1598
|
}
|
|
1608
1599
|
|
|
1600
|
+
/**
|
|
1601
|
+
* Registers a callback which will be called before any change is applied to the editor, allowing you to cancel the change.
|
|
1602
|
+
*/
|
|
1603
|
+
public beforeChange(
|
|
1604
|
+
/**
|
|
1605
|
+
* If the callback returns `false`, the change will be canceled & not applied to the editor.
|
|
1606
|
+
*/
|
|
1607
|
+
callback: (
|
|
1608
|
+
editor: BlockNoteEditor<BSchema, ISchema, SSchema>,
|
|
1609
|
+
context: {
|
|
1610
|
+
getChanges: () => BlocksChanged<BSchema, ISchema, SSchema>;
|
|
1611
|
+
tr: Transaction;
|
|
1612
|
+
},
|
|
1613
|
+
) => boolean | void,
|
|
1614
|
+
): () => void {
|
|
1615
|
+
if (this.headless) {
|
|
1616
|
+
return () => {
|
|
1617
|
+
// noop
|
|
1618
|
+
};
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
return (this.extensions["blockChange"] as BlockChangePlugin).subscribe(
|
|
1622
|
+
(context) => callback(this, context),
|
|
1623
|
+
);
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1609
1626
|
/**
|
|
1610
1627
|
* A callback function that runs whenever the editor's contents change.
|
|
1611
1628
|
*
|
|
@@ -11,6 +11,7 @@ import { createPasteFromClipboardExtension } from "../api/clipboard/fromClipboar
|
|
|
11
11
|
import { createCopyToClipboardExtension } from "../api/clipboard/toClipboard/copyExtension.js";
|
|
12
12
|
import type { ThreadStore } from "../comments/index.js";
|
|
13
13
|
import { BackgroundColorExtension } from "../extensions/BackgroundColor/BackgroundColorExtension.js";
|
|
14
|
+
import { BlockChangePlugin } from "../extensions/BlockChange/BlockChangePlugin.js";
|
|
14
15
|
import { CursorPlugin } from "../extensions/Collaboration/CursorPlugin.js";
|
|
15
16
|
import { SyncPlugin } from "../extensions/Collaboration/SyncPlugin.js";
|
|
16
17
|
import { UndoPlugin } from "../extensions/Collaboration/UndoPlugin.js";
|
|
@@ -90,7 +91,6 @@ type ExtensionOptions<
|
|
|
90
91
|
string | undefined
|
|
91
92
|
>;
|
|
92
93
|
tabBehavior?: "prefer-navigate-ui" | "prefer-indent";
|
|
93
|
-
sideMenuDetection: "viewport" | "editor";
|
|
94
94
|
comments?: {
|
|
95
95
|
threadStore: ThreadStore;
|
|
96
96
|
};
|
|
@@ -133,10 +133,7 @@ export const getBlockNoteExtensions = <
|
|
|
133
133
|
opts.editor,
|
|
134
134
|
);
|
|
135
135
|
ret["linkToolbar"] = new LinkToolbarProsemirrorPlugin(opts.editor);
|
|
136
|
-
ret["sideMenu"] = new SideMenuProsemirrorPlugin(
|
|
137
|
-
opts.editor,
|
|
138
|
-
opts.sideMenuDetection,
|
|
139
|
-
);
|
|
136
|
+
ret["sideMenu"] = new SideMenuProsemirrorPlugin(opts.editor);
|
|
140
137
|
ret["suggestionMenus"] = new SuggestionMenuProseMirrorPlugin(opts.editor);
|
|
141
138
|
ret["filePanel"] = new FilePanelProsemirrorPlugin(opts.editor as any);
|
|
142
139
|
ret["placeholder"] = new PlaceholderPlugin(opts.editor, opts.placeholders);
|
|
@@ -150,6 +147,7 @@ export const getBlockNoteExtensions = <
|
|
|
150
147
|
}
|
|
151
148
|
|
|
152
149
|
ret["nodeSelectionKeyboard"] = new NodeSelectionKeyboardPlugin();
|
|
150
|
+
ret["blockChange"] = new BlockChangePlugin();
|
|
153
151
|
|
|
154
152
|
ret["showSelection"] = new ShowSelectionPlugin(opts.editor);
|
|
155
153
|
|
package/src/exporter/Exporter.ts
CHANGED
|
@@ -90,12 +90,14 @@ export abstract class Exporter<
|
|
|
90
90
|
block: BlockFromConfig<B[keyof B], I, S>,
|
|
91
91
|
nestingLevel: number,
|
|
92
92
|
numberedListIndex: number,
|
|
93
|
+
children?: Array<Awaited<RB>>,
|
|
93
94
|
) {
|
|
94
95
|
return this.mappings.blockMapping[block.type](
|
|
95
96
|
block,
|
|
96
97
|
this,
|
|
97
98
|
nestingLevel,
|
|
98
99
|
numberedListIndex,
|
|
100
|
+
children,
|
|
99
101
|
);
|
|
100
102
|
}
|
|
101
103
|
}
|
package/src/exporter/mapping.ts
CHANGED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Plugin, Transaction } from "prosemirror-state";
|
|
2
|
+
import { getBlocksChangedByTransaction } from "../../api/nodeUtil.js";
|
|
3
|
+
import { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";
|
|
4
|
+
import { BlocksChanged } from "../../index.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This plugin can filter transactions before they are applied to the editor, but with a higher-level API than `filterTransaction` from prosemirror.
|
|
8
|
+
*/
|
|
9
|
+
export class BlockChangePlugin extends BlockNoteExtension {
|
|
10
|
+
public static key() {
|
|
11
|
+
return "blockChange";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
private beforeChangeCallbacks: ((context: {
|
|
15
|
+
getChanges: () => BlocksChanged<any, any, any>;
|
|
16
|
+
tr: Transaction;
|
|
17
|
+
}) => boolean | void)[] = [];
|
|
18
|
+
|
|
19
|
+
constructor() {
|
|
20
|
+
super();
|
|
21
|
+
|
|
22
|
+
this.addProsemirrorPlugin(
|
|
23
|
+
new Plugin({
|
|
24
|
+
filterTransaction: (tr) => {
|
|
25
|
+
let changes:
|
|
26
|
+
| ReturnType<typeof getBlocksChangedByTransaction>
|
|
27
|
+
| undefined = undefined;
|
|
28
|
+
|
|
29
|
+
return this.beforeChangeCallbacks.reduce((acc, cb) => {
|
|
30
|
+
if (acc === false) {
|
|
31
|
+
// We only care that we hit a `false` result, so we can stop iterating.
|
|
32
|
+
return acc;
|
|
33
|
+
}
|
|
34
|
+
return (
|
|
35
|
+
cb({
|
|
36
|
+
getChanges() {
|
|
37
|
+
if (changes) {
|
|
38
|
+
return changes;
|
|
39
|
+
}
|
|
40
|
+
changes = getBlocksChangedByTransaction(tr);
|
|
41
|
+
return changes;
|
|
42
|
+
},
|
|
43
|
+
tr,
|
|
44
|
+
}) !== false
|
|
45
|
+
);
|
|
46
|
+
}, true);
|
|
47
|
+
},
|
|
48
|
+
}),
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public subscribe(
|
|
53
|
+
callback: (context: {
|
|
54
|
+
getChanges: () => BlocksChanged<any, any, any>;
|
|
55
|
+
tr: Transaction;
|
|
56
|
+
}) => boolean | void,
|
|
57
|
+
) {
|
|
58
|
+
this.beforeChangeCallbacks.push(callback);
|
|
59
|
+
|
|
60
|
+
return () => {
|
|
61
|
+
this.beforeChangeCallbacks = this.beforeChangeCallbacks.filter(
|
|
62
|
+
(cb) => cb !== callback,
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -131,6 +131,27 @@ export class CursorPlugin extends BlockNoteExtension {
|
|
|
131
131
|
this.provider.awareness.setLocalStateField("user", user);
|
|
132
132
|
};
|
|
133
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Determine whether the foreground color should be white or black based on a provided background color
|
|
136
|
+
* Inspired by: https://stackoverflow.com/a/3943023
|
|
137
|
+
*
|
|
138
|
+
*/
|
|
139
|
+
public static isDarkColor(bgColor: string): boolean {
|
|
140
|
+
const color = bgColor.charAt(0) === "#" ? bgColor.substring(1, 7) : bgColor;
|
|
141
|
+
const r = parseInt(color.substring(0, 2), 16); // hexToR
|
|
142
|
+
const g = parseInt(color.substring(2, 4), 16); // hexToG
|
|
143
|
+
const b = parseInt(color.substring(4, 6), 16); // hexToB
|
|
144
|
+
const uicolors = [r / 255, g / 255, b / 255];
|
|
145
|
+
const c = uicolors.map((col) => {
|
|
146
|
+
if (col <= 0.03928) {
|
|
147
|
+
return col / 12.92;
|
|
148
|
+
}
|
|
149
|
+
return Math.pow((col + 0.055) / 1.055, 2.4);
|
|
150
|
+
});
|
|
151
|
+
const L = 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2];
|
|
152
|
+
return L <= 0.179;
|
|
153
|
+
}
|
|
154
|
+
|
|
134
155
|
public static defaultCursorRender = (user: CollaborationUser) => {
|
|
135
156
|
const cursorElement = document.createElement("span");
|
|
136
157
|
|
|
@@ -139,12 +160,22 @@ export class CursorPlugin extends BlockNoteExtension {
|
|
|
139
160
|
const caretElement = document.createElement("span");
|
|
140
161
|
caretElement.setAttribute("contentedEditable", "false");
|
|
141
162
|
caretElement.classList.add("bn-collaboration-cursor__caret");
|
|
142
|
-
caretElement.setAttribute(
|
|
163
|
+
caretElement.setAttribute(
|
|
164
|
+
"style",
|
|
165
|
+
`background-color: ${user.color}; color: ${
|
|
166
|
+
CursorPlugin.isDarkColor(user.color) ? "white" : "black"
|
|
167
|
+
}`,
|
|
168
|
+
);
|
|
143
169
|
|
|
144
170
|
const labelElement = document.createElement("span");
|
|
145
171
|
|
|
146
172
|
labelElement.classList.add("bn-collaboration-cursor__label");
|
|
147
|
-
labelElement.setAttribute(
|
|
173
|
+
labelElement.setAttribute(
|
|
174
|
+
"style",
|
|
175
|
+
`background-color: ${user.color}; color: ${
|
|
176
|
+
CursorPlugin.isDarkColor(user.color) ? "white" : "black"
|
|
177
|
+
}`,
|
|
178
|
+
);
|
|
148
179
|
labelElement.insertBefore(document.createTextNode(user.name), null);
|
|
149
180
|
|
|
150
181
|
caretElement.insertBefore(labelElement, null);
|