@blocknote/core 0.42.3 → 0.43.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/BlockNoteExtension-BWw0r8Gy.cjs +2 -0
- package/dist/BlockNoteExtension-BWw0r8Gy.cjs.map +1 -0
- package/dist/BlockNoteExtension-C2X7LW-V.js +25 -0
- package/dist/BlockNoteExtension-C2X7LW-V.js.map +1 -0
- package/dist/BlockNoteSchema-CbSavEwr.js +270 -0
- package/dist/BlockNoteSchema-CbSavEwr.js.map +1 -0
- package/dist/BlockNoteSchema-D8TyvlfU.cjs +2 -0
- package/dist/BlockNoteSchema-D8TyvlfU.cjs.map +1 -0
- package/dist/EventEmitter-CLwfmbqG.cjs +2 -0
- package/dist/EventEmitter-CLwfmbqG.cjs.map +1 -0
- package/dist/EventEmitter-CjSwpTbz.js +27 -0
- package/dist/EventEmitter-CjSwpTbz.js.map +1 -0
- package/dist/ShowSelection-BW37oJ6h.cjs +2 -0
- package/dist/ShowSelection-BW37oJ6h.cjs.map +1 -0
- package/dist/ShowSelection-Dz-NEase.js +43 -0
- package/dist/ShowSelection-Dz-NEase.js.map +1 -0
- package/dist/TrailingNode-BUhuMJrB.js +2096 -0
- package/dist/TrailingNode-BUhuMJrB.js.map +1 -0
- package/dist/TrailingNode-CaT_wbho.cjs +2 -0
- package/dist/TrailingNode-CaT_wbho.cjs.map +1 -0
- package/dist/{blockToNode-DIfPWLH8.js → blockToNode-DBNbhwwC.js} +33 -33
- package/dist/blockToNode-DBNbhwwC.js.map +1 -0
- package/dist/blockToNode-w7H99R6p.cjs.map +1 -1
- package/dist/blocknote.cjs +4 -4
- package/dist/blocknote.cjs.map +1 -1
- package/dist/blocknote.js +2402 -5594
- package/dist/blocknote.js.map +1 -1
- package/dist/blocks.cjs +1 -1
- package/dist/blocks.js +71 -70
- package/dist/blocks.js.map +1 -1
- package/dist/comments.cjs +1 -1
- package/dist/comments.cjs.map +1 -1
- package/dist/comments.js +451 -137
- package/dist/comments.js.map +1 -1
- package/dist/{BlockNoteSchema-Bi-eeHal.js → defaultBlocks-BJtxTOM2.js} +991 -1047
- package/dist/defaultBlocks-BJtxTOM2.js.map +1 -0
- package/dist/defaultBlocks-BxFclIGP.cjs +6 -0
- package/dist/defaultBlocks-BxFclIGP.cjs.map +1 -0
- package/dist/extensions.cjs +2 -0
- package/dist/extensions.cjs.map +1 -0
- package/dist/extensions.js +57 -0
- package/dist/extensions.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/webpack-stats.json +1 -1
- package/dist/yjs.js +1 -1
- package/package.json +9 -3
- package/src/api/nodeConversions/blockToNode.ts +1 -1
- package/src/api/nodeConversions/nodeToBlock.ts +1 -1
- package/src/blocks/Code/block.ts +4 -4
- package/src/blocks/Divider/block.ts +2 -2
- package/src/blocks/File/helpers/render/createAddFileButton.ts +7 -5
- package/src/blocks/Heading/block.ts +23 -20
- package/src/blocks/ListItem/BulletListItem/block.ts +2 -2
- package/src/blocks/ListItem/CheckListItem/block.ts +2 -2
- package/src/blocks/ListItem/NumberedListItem/block.ts +3 -3
- package/src/blocks/ListItem/ToggleListItem/block.ts +2 -2
- package/src/blocks/PageBreak/getPageBreakSlashMenuItems.ts +2 -2
- package/src/blocks/Paragraph/block.ts +2 -2
- package/src/blocks/Quote/block.ts +2 -2
- package/src/blocks/Table/block.ts +4 -3
- package/src/blocks/ToggleWrapper/createToggleWrapper.ts +2 -1
- package/src/comments/extension.ts +353 -0
- package/src/comments/index.ts +2 -1
- package/src/comments/types.ts +8 -0
- package/src/{extensions/Comments → comments}/userstore/UserStore.ts +2 -2
- package/src/editor/BlockNoteEditor.test.ts +2 -23
- package/src/editor/BlockNoteEditor.ts +60 -453
- package/src/editor/BlockNoteExtension.test.ts +103 -0
- package/src/editor/BlockNoteExtension.ts +174 -56
- package/src/editor/managers/EventManager.ts +64 -35
- package/src/editor/managers/ExtensionManager/extensions.ts +214 -0
- package/src/editor/managers/ExtensionManager/index.ts +514 -0
- package/src/editor/managers/ExtensionManager/symbol.ts +6 -0
- package/src/editor/managers/SelectionManager.ts +5 -1
- package/src/editor/managers/StateManager.ts +29 -17
- package/src/editor/managers/index.ts +1 -5
- package/src/extensions/BlockChange/{BlockChangePlugin.ts → BlockChange.ts} +27 -29
- package/src/extensions/Collaboration/{ForkYDocPlugin.test.ts → ForkYDoc.test.ts} +6 -5
- package/src/extensions/Collaboration/ForkYDoc.ts +158 -0
- package/src/extensions/Collaboration/YCursorPlugin.ts +183 -0
- package/src/extensions/Collaboration/YSync.ts +16 -0
- package/src/extensions/Collaboration/YUndo.ts +12 -0
- package/src/extensions/Collaboration/schemaMigration/SchemaMigration.ts +59 -0
- package/src/extensions/DropCursor/DropCursor.ts +26 -0
- package/src/extensions/FilePanel/FilePanel.ts +41 -0
- package/src/extensions/FormattingToolbar/FormattingToolbar.ts +119 -0
- package/src/extensions/History/History.ts +11 -0
- package/src/extensions/LinkToolbar/LinkToolbar.ts +121 -0
- package/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboard.ts +74 -0
- package/src/extensions/Placeholder/Placeholder.ts +148 -0
- package/src/extensions/PreviousBlockType/{PreviousBlockTypePlugin.ts → PreviousBlockType.ts} +9 -13
- package/src/extensions/ShowSelection/{ShowSelectionPlugin.ts → ShowSelection.ts} +27 -33
- package/src/extensions/SideMenu/{SideMenuPlugin.ts → SideMenu.ts} +63 -83
- package/src/extensions/SuggestionMenu/{SuggestionPlugin.ts → SuggestionMenu.ts} +71 -77
- package/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts +29 -44
- package/src/extensions/TableHandles/{TableHandlesPlugin.ts → TableHandles.ts} +416 -437
- package/src/extensions/TrailingNode/{TrailingNodeExtension.ts → TrailingNode.ts} +8 -17
- package/src/extensions/index.ts +24 -0
- package/src/extensions/{BackgroundColor → tiptap-extensions/BackgroundColor}/BackgroundColorExtension.ts +1 -1
- package/src/extensions/{KeyboardShortcuts → tiptap-extensions/KeyboardShortcuts}/KeyboardShortcutsExtension.ts +21 -16
- package/src/extensions/{TextColor → tiptap-extensions/TextColor}/TextColorExtension.ts +1 -1
- package/src/extensions/tiptap-extensions/index.ts +31 -0
- package/src/index.ts +1 -13
- package/src/schema/blocks/createSpec.ts +14 -11
- package/src/schema/blocks/internal.ts +2 -2
- package/src/schema/blocks/types.ts +8 -5
- package/src/schema/schema.ts +11 -36
- package/src/util/topo-sort.ts +46 -0
- package/types/src/comments/extension.d.ts +70 -0
- package/types/src/comments/index.d.ts +2 -1
- package/types/src/comments/types.d.ts +8 -0
- package/types/src/{extensions/Comments → comments}/userstore/UserStore.d.ts +2 -2
- package/types/src/editor/BlockNoteEditor.d.ts +34 -105
- package/types/src/editor/BlockNoteExtension.d.ts +87 -22
- package/types/src/editor/managers/EventManager.d.ts +25 -16
- package/types/src/editor/managers/ExtensionManager/extensions.d.ts +8 -0
- package/types/src/editor/managers/ExtensionManager/index.d.ts +83 -0
- package/types/src/editor/managers/ExtensionManager/symbol.d.ts +5 -0
- package/types/src/editor/managers/StateManager.d.ts +1 -12
- package/types/src/editor/managers/index.d.ts +1 -2
- package/types/src/extensions/BlockChange/BlockChange.d.ts +16 -0
- package/types/src/extensions/Collaboration/ForkYDoc.d.ts +34 -0
- package/types/src/extensions/Collaboration/ForkYDoc.test.d.ts +1 -0
- package/types/src/extensions/Collaboration/YCursorPlugin.d.ts +24 -0
- package/types/src/extensions/Collaboration/YSync.d.ts +8 -0
- package/types/src/extensions/Collaboration/YUndo.d.ts +12 -0
- package/types/src/extensions/Collaboration/schemaMigration/SchemaMigration.d.ts +8 -0
- package/types/src/extensions/DropCursor/DropCursor.d.ts +5 -0
- package/types/src/extensions/FilePanel/FilePanel.d.ts +11 -0
- package/types/src/extensions/FormattingToolbar/FormattingToolbar.d.ts +9 -0
- package/types/src/extensions/History/History.d.ts +6 -0
- package/types/src/extensions/LinkToolbar/LinkToolbar.d.ts +24 -0
- package/types/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboard.d.ts +5 -0
- package/types/src/extensions/Placeholder/Placeholder.d.ts +6 -0
- package/types/src/extensions/PreviousBlockType/{PreviousBlockTypePlugin.d.ts → PreviousBlockType.d.ts} +9 -5
- package/types/src/extensions/ShowSelection/ShowSelection.d.ts +21 -0
- package/types/src/extensions/SideMenu/{SideMenuPlugin.d.ts → SideMenu.d.ts} +11 -15
- package/types/src/extensions/SuggestionMenu/SuggestionMenu.d.ts +54 -0
- package/types/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.d.ts +1 -1
- package/types/src/extensions/TableHandles/{TableHandlesPlugin.d.ts → TableHandles.d.ts} +28 -31
- package/types/src/extensions/TrailingNode/TrailingNode.d.ts +8 -0
- package/types/src/extensions/index.d.ts +24 -0
- package/types/src/extensions/{KeyboardShortcuts → tiptap-extensions/KeyboardShortcuts}/KeyboardShortcutsExtension.d.ts +1 -1
- package/types/src/extensions/tiptap-extensions/index.d.ts +11 -0
- package/types/src/index.d.ts +1 -13
- package/types/src/schema/blocks/createSpec.d.ts +4 -4
- package/types/src/schema/blocks/internal.d.ts +2 -2
- package/types/src/schema/blocks/types.d.ts +5 -5
- package/types/src/util/topo-sort.d.ts +8 -0
- package/dist/BlockNoteSchema-Bi-eeHal.js.map +0 -1
- package/dist/BlockNoteSchema-DjDaA2C3.cjs +0 -6
- package/dist/BlockNoteSchema-DjDaA2C3.cjs.map +0 -1
- package/dist/blockToNode-DIfPWLH8.js.map +0 -1
- package/src/comments/models/User.ts +0 -8
- package/src/editor/BlockNoteExtensions.ts +0 -325
- package/src/editor/managers/CollaborationManager.ts +0 -212
- package/src/editor/managers/ExtensionManager.ts +0 -130
- package/src/extensions/Collaboration/CursorPlugin.ts +0 -189
- package/src/extensions/Collaboration/ForkYDocPlugin.ts +0 -192
- package/src/extensions/Collaboration/SyncPlugin.ts +0 -18
- package/src/extensions/Collaboration/UndoPlugin.ts +0 -18
- package/src/extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.ts +0 -59
- package/src/extensions/Comments/CommentsPlugin.ts +0 -392
- package/src/extensions/FilePanel/FilePanelPlugin.ts +0 -206
- package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +0 -363
- package/src/extensions/LinkToolbar/LinkToolbarPlugin.ts +0 -380
- package/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.ts +0 -75
- package/src/extensions/Placeholder/PlaceholderPlugin.ts +0 -147
- package/types/src/comments/models/User.d.ts +0 -8
- package/types/src/editor/BlockNoteExtensions.d.ts +0 -43
- package/types/src/editor/managers/CollaborationManager.d.ts +0 -115
- package/types/src/editor/managers/ExtensionManager.d.ts +0 -68
- package/types/src/extensions/BlockChange/BlockChangePlugin.d.ts +0 -15
- package/types/src/extensions/Collaboration/CursorPlugin.d.ts +0 -37
- package/types/src/extensions/Collaboration/ForkYDocPlugin.d.ts +0 -41
- package/types/src/extensions/Collaboration/SyncPlugin.d.ts +0 -7
- package/types/src/extensions/Collaboration/UndoPlugin.d.ts +0 -9
- package/types/src/extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.d.ts +0 -7
- package/types/src/extensions/Comments/CommentsPlugin.d.ts +0 -66
- package/types/src/extensions/FilePanel/FilePanelPlugin.d.ts +0 -31
- package/types/src/extensions/FormattingToolbar/FormattingToolbarPlugin.d.ts +0 -41
- package/types/src/extensions/LinkToolbar/LinkToolbarPlugin.d.ts +0 -42
- package/types/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.d.ts +0 -5
- package/types/src/extensions/Placeholder/PlaceholderPlugin.d.ts +0 -6
- package/types/src/extensions/ShowSelection/ShowSelectionPlugin.d.ts +0 -15
- package/types/src/extensions/SuggestionMenu/SuggestionPlugin.d.ts +0 -31
- package/types/src/extensions/TrailingNode/TrailingNodeExtension.d.ts +0 -13
- /package/src/{extensions/Comments/CommentMark.ts → comments/mark.ts} +0 -0
- /package/src/extensions/{HardBreak → tiptap-extensions/HardBreak}/HardBreak.ts +0 -0
- /package/src/extensions/{Suggestions → tiptap-extensions/Suggestions}/SuggestionMarks.ts +0 -0
- /package/src/extensions/{TextAlignment → tiptap-extensions/TextAlignment}/TextAlignmentExtension.ts +0 -0
- /package/src/extensions/{UniqueID → tiptap-extensions/UniqueID}/UniqueID.ts +0 -0
- /package/types/src/{extensions/Comments/CommentMark.d.ts → comments/mark.d.ts} +0 -0
- /package/types/src/{extensions/Collaboration/ForkYDocPlugin.test.d.ts → editor/BlockNoteExtension.test.d.ts} +0 -0
- /package/types/src/extensions/{BackgroundColor → tiptap-extensions/BackgroundColor}/BackgroundColorExtension.d.ts +0 -0
- /package/types/src/extensions/{HardBreak → tiptap-extensions/HardBreak}/HardBreak.d.ts +0 -0
- /package/types/src/extensions/{Suggestions → tiptap-extensions/Suggestions}/SuggestionMarks.d.ts +0 -0
- /package/types/src/extensions/{TextAlignment → tiptap-extensions/TextAlignment}/TextAlignmentExtension.d.ts +0 -0
- /package/types/src/extensions/{TextColor → tiptap-extensions/TextColor}/TextColorExtension.d.ts +0 -0
- /package/types/src/extensions/{UniqueID → tiptap-extensions/UniqueID}/UniqueID.d.ts +0 -0
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InputRule,
|
|
3
|
+
inputRules as inputRulesPlugin,
|
|
4
|
+
} from "@handlewithcare/prosemirror-inputrules";
|
|
5
|
+
import {
|
|
6
|
+
AnyExtension as AnyTiptapExtension,
|
|
7
|
+
Extension as TiptapExtension,
|
|
8
|
+
} from "@tiptap/core";
|
|
9
|
+
import { keymap } from "@tiptap/pm/keymap";
|
|
10
|
+
import { Plugin } from "prosemirror-state";
|
|
11
|
+
import { updateBlockTr } from "../../../api/blockManipulation/commands/updateBlock/updateBlock.js";
|
|
12
|
+
import { getBlockInfoFromTransaction } from "../../../api/getBlockInfoFromPos.js";
|
|
13
|
+
import { sortByDependencies } from "../../../util/topo-sort.js";
|
|
14
|
+
import type {
|
|
15
|
+
BlockNoteEditor,
|
|
16
|
+
BlockNoteEditorOptions,
|
|
17
|
+
} from "../../BlockNoteEditor.js";
|
|
18
|
+
import type {
|
|
19
|
+
Extension,
|
|
20
|
+
ExtensionFactoryInstance,
|
|
21
|
+
ExtensionFactory,
|
|
22
|
+
} from "../../BlockNoteExtension.js";
|
|
23
|
+
import { originalFactorySymbol } from "./symbol.js";
|
|
24
|
+
import {
|
|
25
|
+
getDefaultExtensions,
|
|
26
|
+
getDefaultTiptapExtensions,
|
|
27
|
+
} from "./extensions.js";
|
|
28
|
+
|
|
29
|
+
export class ExtensionManager {
|
|
30
|
+
/**
|
|
31
|
+
* A set of extension keys which are disabled by the options
|
|
32
|
+
*/
|
|
33
|
+
private disabledExtensions = new Set<string>();
|
|
34
|
+
/**
|
|
35
|
+
* A list of all the extensions that are registered to the editor
|
|
36
|
+
*/
|
|
37
|
+
private extensions: Extension[] = [];
|
|
38
|
+
/**
|
|
39
|
+
* A map of all the abort controllers for each extension that has an init method defined
|
|
40
|
+
*/
|
|
41
|
+
private abortMap = new Map<Extension, AbortController>();
|
|
42
|
+
/**
|
|
43
|
+
* A map of all the extension factories that are registered to the editor
|
|
44
|
+
*/
|
|
45
|
+
private extensionFactories = new Map<ExtensionFactory, Extension>();
|
|
46
|
+
/**
|
|
47
|
+
* Because a single blocknote extension can both have it's own prosemirror plugins & additional generated ones (e.g. keymap & input rules plugins)
|
|
48
|
+
* We need to keep track of all the plugins for each extension, so that we can remove them when the extension is unregistered
|
|
49
|
+
*/
|
|
50
|
+
private extensionPlugins: Map<Extension, Plugin[]> = new Map();
|
|
51
|
+
|
|
52
|
+
constructor(
|
|
53
|
+
private editor: BlockNoteEditor<any, any, any>,
|
|
54
|
+
private options: BlockNoteEditorOptions<any, any, any>,
|
|
55
|
+
) {
|
|
56
|
+
/**
|
|
57
|
+
* When the editor is first mounted, we need to initialize all the extensions
|
|
58
|
+
*/
|
|
59
|
+
editor.onMount(() => {
|
|
60
|
+
for (const extension of this.extensions) {
|
|
61
|
+
// If the extension has an init function, we can initialize it, otherwise, it is already added to the editor
|
|
62
|
+
if (extension.mount) {
|
|
63
|
+
// We create an abort controller for each extension, so that we can abort the extension when the editor is unmounted
|
|
64
|
+
const abortController = new window.AbortController();
|
|
65
|
+
const unmountCallback = extension.mount({
|
|
66
|
+
dom: editor.prosemirrorView.dom,
|
|
67
|
+
root: editor.prosemirrorView.root,
|
|
68
|
+
signal: abortController.signal,
|
|
69
|
+
});
|
|
70
|
+
// If the extension returns a method to unmount it, we can register it to be called when the abort controller is aborted
|
|
71
|
+
if (unmountCallback) {
|
|
72
|
+
abortController.signal.addEventListener("abort", () => {
|
|
73
|
+
unmountCallback();
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
// Keep track of the abort controller for each extension, so that we can abort it when the editor is unmounted
|
|
77
|
+
this.abortMap.set(extension, abortController);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* When the editor is unmounted, we need to abort all the extensions' abort controllers
|
|
84
|
+
*/
|
|
85
|
+
editor.onUnmount(() => {
|
|
86
|
+
for (const [extension, abortController] of this.abortMap.entries()) {
|
|
87
|
+
// No longer track the abort controller for this extension
|
|
88
|
+
this.abortMap.delete(extension);
|
|
89
|
+
// Abort each extension's abort controller
|
|
90
|
+
abortController.abort();
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// TODO do disabled extensions need to be only for editor base extensions? Or all of them?
|
|
95
|
+
this.disabledExtensions = new Set(options.disableExtensions || []);
|
|
96
|
+
|
|
97
|
+
// Add the default extensions
|
|
98
|
+
for (const extension of getDefaultExtensions(this.editor, this.options)) {
|
|
99
|
+
this.addExtension(extension);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Add the extensions from the options
|
|
103
|
+
for (const extension of this.options.extensions ?? []) {
|
|
104
|
+
this.addExtension(extension);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Add the extensions from blocks specs
|
|
108
|
+
for (const block of Object.values(this.editor.schema.blockSpecs)) {
|
|
109
|
+
for (const extension of block.extensions ?? []) {
|
|
110
|
+
this.addExtension(extension);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Register one or more extensions to the editor after the editor is initialized.
|
|
117
|
+
*
|
|
118
|
+
* This allows users to switch on & off extensions "at runtime".
|
|
119
|
+
*/
|
|
120
|
+
public registerExtension(
|
|
121
|
+
extension:
|
|
122
|
+
| Extension
|
|
123
|
+
| ExtensionFactoryInstance
|
|
124
|
+
| (Extension | ExtensionFactoryInstance)[],
|
|
125
|
+
): void {
|
|
126
|
+
const extensions = ([] as (Extension | ExtensionFactoryInstance)[])
|
|
127
|
+
.concat(extension)
|
|
128
|
+
.filter(Boolean) as (Extension | ExtensionFactoryInstance)[];
|
|
129
|
+
|
|
130
|
+
if (!extensions.length) {
|
|
131
|
+
// eslint-disable-next-line no-console
|
|
132
|
+
console.warn(`No extensions found to register`, extension);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const registeredExtensions = extensions
|
|
137
|
+
.map((extension) => this.addExtension(extension))
|
|
138
|
+
.filter(Boolean) as Extension[];
|
|
139
|
+
|
|
140
|
+
const pluginsToAdd = new Set<Plugin>();
|
|
141
|
+
for (const extension of registeredExtensions) {
|
|
142
|
+
if (extension?.tiptapExtensions) {
|
|
143
|
+
// This is necessary because this can only switch out prosemirror plugins at runtime,
|
|
144
|
+
// it can't switch out Tiptap extensions since that can have more widespread effects (since a Tiptap extension can even add/remove to the schema).
|
|
145
|
+
|
|
146
|
+
// eslint-disable-next-line no-console
|
|
147
|
+
console.warn(
|
|
148
|
+
`Extension ${extension.key} has tiptap extensions, but these cannot be changed after initializing the editor. Please separate the extension into multiple extensions if you want to add them, or re-initialize the editor.`,
|
|
149
|
+
extension,
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (extension?.inputRules?.length) {
|
|
154
|
+
// This is necessary because input rules are defined in a single prosemirror plugin which cannot be re-initialized.
|
|
155
|
+
// eslint-disable-next-line no-console
|
|
156
|
+
console.warn(
|
|
157
|
+
`Extension ${extension.key} has input rules, but these cannot be changed after initializing the editor. Please separate the extension into multiple extensions if you want to add them, or re-initialize the editor.`,
|
|
158
|
+
extension,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
this.getProsemirrorPluginsFromExtension(extension).plugins.forEach(
|
|
163
|
+
(plugin) => {
|
|
164
|
+
pluginsToAdd.add(plugin);
|
|
165
|
+
},
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// TODO there isn't a great way to do sorting right now. This is something that should be improved in the future.
|
|
170
|
+
// So, we just append to the end of the list for now.
|
|
171
|
+
this.updatePlugins((plugins) => [...plugins, ...pluginsToAdd]);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Register an extension to the editor
|
|
176
|
+
* @param extension - The extension to register
|
|
177
|
+
* @returns The extension instance
|
|
178
|
+
*/
|
|
179
|
+
private addExtension(
|
|
180
|
+
extension: Extension | ExtensionFactoryInstance,
|
|
181
|
+
): Extension | undefined {
|
|
182
|
+
let instance: Extension;
|
|
183
|
+
if (typeof extension === "function") {
|
|
184
|
+
instance = extension({ editor: this.editor });
|
|
185
|
+
} else {
|
|
186
|
+
instance = extension;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (!instance || this.disabledExtensions.has(instance.key)) {
|
|
190
|
+
return undefined as any;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Now that we know that the extension is not disabled, we can add it to the extension factories
|
|
194
|
+
if (typeof extension === "function") {
|
|
195
|
+
const originalFactory = (instance as any)[originalFactorySymbol] as (
|
|
196
|
+
...args: any[]
|
|
197
|
+
) => ExtensionFactoryInstance;
|
|
198
|
+
|
|
199
|
+
if (typeof originalFactory === "function") {
|
|
200
|
+
this.extensionFactories.set(originalFactory, instance);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
this.extensions.push(instance);
|
|
205
|
+
|
|
206
|
+
return instance as any;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Resolve an extension or a list of extensions into a list of extension instances
|
|
211
|
+
* @param toResolve - The extension or list of extensions to resolve
|
|
212
|
+
* @returns A list of extension instances
|
|
213
|
+
*/
|
|
214
|
+
private resolveExtensions(
|
|
215
|
+
toResolve:
|
|
216
|
+
| undefined
|
|
217
|
+
| string
|
|
218
|
+
| Extension
|
|
219
|
+
| ExtensionFactory
|
|
220
|
+
| (Extension | ExtensionFactory | string | undefined)[],
|
|
221
|
+
): Extension[] {
|
|
222
|
+
const extensions = [] as Extension[];
|
|
223
|
+
if (typeof toResolve === "function") {
|
|
224
|
+
const instance = this.extensionFactories.get(toResolve);
|
|
225
|
+
if (instance) {
|
|
226
|
+
extensions.push(instance);
|
|
227
|
+
}
|
|
228
|
+
} else if (Array.isArray(toResolve)) {
|
|
229
|
+
for (const extension of toResolve) {
|
|
230
|
+
extensions.push(...this.resolveExtensions(extension));
|
|
231
|
+
}
|
|
232
|
+
} else if (typeof toResolve === "object" && "key" in toResolve) {
|
|
233
|
+
extensions.push(toResolve);
|
|
234
|
+
} else if (typeof toResolve === "string") {
|
|
235
|
+
const instance = this.extensions.find((e) => e.key === toResolve);
|
|
236
|
+
if (instance) {
|
|
237
|
+
extensions.push(instance);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return extensions;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Unregister an extension from the editor
|
|
245
|
+
* @param toUnregister - The extension to unregister
|
|
246
|
+
* @returns void
|
|
247
|
+
*/
|
|
248
|
+
public unregisterExtension(
|
|
249
|
+
toUnregister:
|
|
250
|
+
| undefined
|
|
251
|
+
| string
|
|
252
|
+
| Extension
|
|
253
|
+
| ExtensionFactory
|
|
254
|
+
| (Extension | ExtensionFactory | string | undefined)[],
|
|
255
|
+
): void {
|
|
256
|
+
const extensions = this.resolveExtensions(toUnregister);
|
|
257
|
+
|
|
258
|
+
if (!extensions.length) {
|
|
259
|
+
// eslint-disable-next-line no-console
|
|
260
|
+
console.warn(`No extensions found to unregister`, toUnregister);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
let didWarn = false;
|
|
264
|
+
|
|
265
|
+
const pluginsToRemove = new Set<Plugin>();
|
|
266
|
+
for (const extension of extensions) {
|
|
267
|
+
this.extensions = this.extensions.filter((e) => e !== extension);
|
|
268
|
+
this.extensionFactories.forEach((instance, factory) => {
|
|
269
|
+
if (instance === extension) {
|
|
270
|
+
this.extensionFactories.delete(factory);
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
this.abortMap.get(extension)?.abort();
|
|
274
|
+
this.abortMap.delete(extension);
|
|
275
|
+
|
|
276
|
+
const plugins = this.extensionPlugins.get(extension);
|
|
277
|
+
plugins?.forEach((plugin) => {
|
|
278
|
+
pluginsToRemove.add(plugin);
|
|
279
|
+
});
|
|
280
|
+
this.extensionPlugins.delete(extension);
|
|
281
|
+
|
|
282
|
+
if (extension.tiptapExtensions && !didWarn) {
|
|
283
|
+
didWarn = true;
|
|
284
|
+
// eslint-disable-next-line no-console
|
|
285
|
+
console.warn(
|
|
286
|
+
`Extension ${extension.key} has tiptap extensions, but they will not be removed. Please separate the extension into multiple extensions if you want to remove them, or re-initialize the editor.`,
|
|
287
|
+
toUnregister,
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
this.updatePlugins((plugins) =>
|
|
293
|
+
plugins.filter((plugin) => !pluginsToRemove.has(plugin)),
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Allows resetting the current prosemirror state's plugins
|
|
299
|
+
* @param update - A function that takes the current plugins and returns the new plugins
|
|
300
|
+
* @returns void
|
|
301
|
+
*/
|
|
302
|
+
private updatePlugins(update: (plugins: Plugin[]) => Plugin[]): void {
|
|
303
|
+
const currentState = this.editor.prosemirrorState;
|
|
304
|
+
|
|
305
|
+
const state = currentState.reconfigure({
|
|
306
|
+
plugins: update(currentState.plugins.slice()),
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
this.editor.prosemirrorView.updateState(state);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Get all the extensions that are registered to the editor
|
|
314
|
+
*/
|
|
315
|
+
public getTiptapExtensions(): AnyTiptapExtension[] {
|
|
316
|
+
// Start with the default tiptap extensions
|
|
317
|
+
const tiptapExtensions = getDefaultTiptapExtensions(
|
|
318
|
+
this.editor,
|
|
319
|
+
this.options,
|
|
320
|
+
);
|
|
321
|
+
// TODO filter out the default extensions via the disabledExtensions set?
|
|
322
|
+
|
|
323
|
+
const getPriority = sortByDependencies(this.extensions);
|
|
324
|
+
|
|
325
|
+
const inputRulesByPriority = new Map<number, InputRule[]>();
|
|
326
|
+
for (const extension of this.extensions) {
|
|
327
|
+
if (extension.tiptapExtensions) {
|
|
328
|
+
tiptapExtensions.push(...extension.tiptapExtensions);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const priority = getPriority(extension.key);
|
|
332
|
+
|
|
333
|
+
const { plugins: prosemirrorPlugins, inputRules } =
|
|
334
|
+
this.getProsemirrorPluginsFromExtension(extension);
|
|
335
|
+
// Sometimes a blocknote extension might need to make additional prosemirror plugins, so we generate them here
|
|
336
|
+
if (prosemirrorPlugins.length) {
|
|
337
|
+
tiptapExtensions.push(
|
|
338
|
+
TiptapExtension.create({
|
|
339
|
+
name: extension.key,
|
|
340
|
+
priority,
|
|
341
|
+
addProseMirrorPlugins: () => prosemirrorPlugins,
|
|
342
|
+
}),
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
if (inputRules.length) {
|
|
346
|
+
if (!inputRulesByPriority.has(priority)) {
|
|
347
|
+
inputRulesByPriority.set(priority, []);
|
|
348
|
+
}
|
|
349
|
+
inputRulesByPriority.get(priority)!.push(...inputRules);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Collect all input rules into 1 extension to reduce conflicts
|
|
354
|
+
tiptapExtensions.push(
|
|
355
|
+
TiptapExtension.create({
|
|
356
|
+
name: "blocknote-input-rules",
|
|
357
|
+
addProseMirrorPlugins() {
|
|
358
|
+
const rules = [] as InputRule[];
|
|
359
|
+
Array.from(inputRulesByPriority.keys())
|
|
360
|
+
// We sort the rules by their priority (the key)
|
|
361
|
+
.sort()
|
|
362
|
+
.reverse()
|
|
363
|
+
.forEach((priority) => {
|
|
364
|
+
// Append in reverse priority order
|
|
365
|
+
rules.push(...inputRulesByPriority.get(priority)!);
|
|
366
|
+
});
|
|
367
|
+
return [inputRulesPlugin({ rules })];
|
|
368
|
+
},
|
|
369
|
+
}),
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
// Add any tiptap extensions from the `_tiptapOptions`
|
|
373
|
+
for (const extension of this.options._tiptapOptions?.extensions ?? []) {
|
|
374
|
+
tiptapExtensions.push(extension);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return tiptapExtensions;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* This maps a blocknote extension into an array of Prosemirror plugins if it has any of the following:
|
|
382
|
+
* - plugins
|
|
383
|
+
* - keyboard shortcuts
|
|
384
|
+
* - input rules
|
|
385
|
+
*/
|
|
386
|
+
private getProsemirrorPluginsFromExtension(extension: Extension): {
|
|
387
|
+
plugins: Plugin[];
|
|
388
|
+
inputRules: InputRule[];
|
|
389
|
+
} {
|
|
390
|
+
const plugins: Plugin[] = [...(extension.prosemirrorPlugins ?? [])];
|
|
391
|
+
const inputRules: InputRule[] = [];
|
|
392
|
+
if (
|
|
393
|
+
!extension.prosemirrorPlugins?.length &&
|
|
394
|
+
!Object.keys(extension.keyboardShortcuts || {}).length &&
|
|
395
|
+
!extension.inputRules?.length
|
|
396
|
+
) {
|
|
397
|
+
// We can bail out early if the extension has no features to add to the tiptap editor
|
|
398
|
+
return { plugins, inputRules };
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
this.extensionPlugins.set(extension, plugins);
|
|
402
|
+
|
|
403
|
+
if (extension.inputRules?.length) {
|
|
404
|
+
inputRules.push(
|
|
405
|
+
...extension.inputRules.map((inputRule) => {
|
|
406
|
+
return new InputRule(inputRule.find, (state, match, start, end) => {
|
|
407
|
+
const replaceWith = inputRule.replace({
|
|
408
|
+
match,
|
|
409
|
+
range: { from: start, to: end },
|
|
410
|
+
editor: this.editor,
|
|
411
|
+
});
|
|
412
|
+
if (replaceWith) {
|
|
413
|
+
const cursorPosition = this.editor.getTextCursorPosition();
|
|
414
|
+
|
|
415
|
+
if (
|
|
416
|
+
this.editor.schema.blockSchema[cursorPosition.block.type]
|
|
417
|
+
.content !== "inline"
|
|
418
|
+
) {
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const blockInfo = getBlockInfoFromTransaction(state.tr);
|
|
423
|
+
const tr = state.tr.deleteRange(start, end);
|
|
424
|
+
|
|
425
|
+
updateBlockTr(tr, blockInfo.bnBlock.beforePos, replaceWith);
|
|
426
|
+
return tr;
|
|
427
|
+
}
|
|
428
|
+
return null;
|
|
429
|
+
});
|
|
430
|
+
}),
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
if (Object.keys(extension.keyboardShortcuts || {}).length) {
|
|
435
|
+
plugins.push(
|
|
436
|
+
keymap(
|
|
437
|
+
Object.fromEntries(
|
|
438
|
+
Object.entries(extension.keyboardShortcuts!).map(([key, value]) => [
|
|
439
|
+
key,
|
|
440
|
+
() => value({ editor: this.editor }),
|
|
441
|
+
]),
|
|
442
|
+
),
|
|
443
|
+
),
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
return { plugins, inputRules };
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Get all extensions
|
|
452
|
+
*/
|
|
453
|
+
public getExtensions(): Map<string, Extension> {
|
|
454
|
+
return new Map(
|
|
455
|
+
this.extensions.map((extension) => [extension.key, extension]),
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Get a specific extension by it's instance
|
|
461
|
+
*/
|
|
462
|
+
public getExtension<
|
|
463
|
+
const Ext extends Extension | ExtensionFactory = Extension,
|
|
464
|
+
>(
|
|
465
|
+
extension: string,
|
|
466
|
+
):
|
|
467
|
+
| (Ext extends Extension
|
|
468
|
+
? Ext
|
|
469
|
+
: Ext extends ExtensionFactory
|
|
470
|
+
? ReturnType<ReturnType<Ext>>
|
|
471
|
+
: never)
|
|
472
|
+
| undefined;
|
|
473
|
+
public getExtension<const T extends ExtensionFactory>(
|
|
474
|
+
extension: T,
|
|
475
|
+
): ReturnType<ReturnType<T>> | undefined;
|
|
476
|
+
public getExtension<const T extends ExtensionFactory | string = string>(
|
|
477
|
+
extension: T,
|
|
478
|
+
):
|
|
479
|
+
| (T extends ExtensionFactory
|
|
480
|
+
? ReturnType<ReturnType<T>>
|
|
481
|
+
: T extends string
|
|
482
|
+
? Extension
|
|
483
|
+
: never)
|
|
484
|
+
| undefined {
|
|
485
|
+
if (typeof extension === "string") {
|
|
486
|
+
const instance = this.extensions.find((e) => e.key === extension);
|
|
487
|
+
if (!instance) {
|
|
488
|
+
return undefined;
|
|
489
|
+
}
|
|
490
|
+
return instance as any;
|
|
491
|
+
} else if (typeof extension === "function") {
|
|
492
|
+
const instance = this.extensionFactories.get(extension);
|
|
493
|
+
if (!instance) {
|
|
494
|
+
return undefined;
|
|
495
|
+
}
|
|
496
|
+
return instance as any;
|
|
497
|
+
}
|
|
498
|
+
throw new Error(`Invalid extension type: ${typeof extension}`);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Check if an extension exists
|
|
503
|
+
*/
|
|
504
|
+
public hasExtension(key: string | Extension | ExtensionFactory): boolean {
|
|
505
|
+
if (typeof key === "string") {
|
|
506
|
+
return this.extensions.some((e) => e.key === key);
|
|
507
|
+
} else if (typeof key === "object" && "key" in key) {
|
|
508
|
+
return this.extensions.some((e) => e.key === key.key);
|
|
509
|
+
} else if (typeof key === "function") {
|
|
510
|
+
return this.extensionFactories.has(key);
|
|
511
|
+
}
|
|
512
|
+
return false;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
@@ -1,21 +1,10 @@
|
|
|
1
|
-
import { redo, undo } from "@tiptap/pm/history";
|
|
2
1
|
import { Command, Transaction } from "prosemirror-state";
|
|
2
|
+
import type { YUndoExtension } from "../../extensions/Collaboration/YUndo.js";
|
|
3
|
+
import type { HistoryExtension } from "../../extensions/History/History.js";
|
|
3
4
|
import { BlockNoteEditor } from "../BlockNoteEditor.js";
|
|
4
5
|
|
|
5
6
|
export class StateManager {
|
|
6
|
-
constructor(
|
|
7
|
-
private editor: BlockNoteEditor,
|
|
8
|
-
private options?: {
|
|
9
|
-
/**
|
|
10
|
-
* Swap the default undo command with a custom command.
|
|
11
|
-
*/
|
|
12
|
-
undo?: typeof undo;
|
|
13
|
-
/**
|
|
14
|
-
* Swap the default redo command with a custom command.
|
|
15
|
-
*/
|
|
16
|
-
redo?: typeof redo;
|
|
17
|
-
},
|
|
18
|
-
) {}
|
|
7
|
+
constructor(private editor: BlockNoteEditor<any, any, any>) {}
|
|
19
8
|
|
|
20
9
|
/**
|
|
21
10
|
* Stores the currently active transaction, which is the accumulated transaction from all {@link dispatch} calls during a {@link transact} calls
|
|
@@ -225,14 +214,37 @@ export class StateManager {
|
|
|
225
214
|
/**
|
|
226
215
|
* Undo the last action.
|
|
227
216
|
*/
|
|
228
|
-
public undo() {
|
|
229
|
-
|
|
217
|
+
public undo(): boolean {
|
|
218
|
+
// Purposefully not using the UndoPlugin to not import y-prosemirror when not needed
|
|
219
|
+
const undoPlugin = this.editor.getExtension<typeof YUndoExtension>("yUndo");
|
|
220
|
+
if (undoPlugin) {
|
|
221
|
+
return this.exec(undoPlugin.undoCommand);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const historyPlugin =
|
|
225
|
+
this.editor.getExtension<typeof HistoryExtension>("history");
|
|
226
|
+
if (historyPlugin) {
|
|
227
|
+
return this.exec(historyPlugin.undoCommand);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
throw new Error("No undo plugin found");
|
|
230
231
|
}
|
|
231
232
|
|
|
232
233
|
/**
|
|
233
234
|
* Redo the last action.
|
|
234
235
|
*/
|
|
235
236
|
public redo() {
|
|
236
|
-
|
|
237
|
+
const undoPlugin = this.editor.getExtension<typeof YUndoExtension>("yUndo");
|
|
238
|
+
if (undoPlugin) {
|
|
239
|
+
return this.exec(undoPlugin.redoCommand);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const historyPlugin =
|
|
243
|
+
this.editor.getExtension<typeof HistoryExtension>("history");
|
|
244
|
+
if (historyPlugin) {
|
|
245
|
+
return this.exec(historyPlugin.redoCommand);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
throw new Error("No redo plugin found");
|
|
237
249
|
}
|
|
238
250
|
}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
export { BlockManager } from "./BlockManager.js";
|
|
2
|
-
export {
|
|
3
|
-
CollaborationManager,
|
|
4
|
-
type CollaborationOptions,
|
|
5
|
-
} from "./CollaborationManager.js";
|
|
6
2
|
export { EventManager } from "./EventManager.js";
|
|
7
3
|
export { ExportManager } from "./ExportManager.js";
|
|
8
|
-
export { ExtensionManager } from "./ExtensionManager.js";
|
|
4
|
+
export { ExtensionManager } from "./ExtensionManager/index.js";
|
|
9
5
|
export { SelectionManager } from "./SelectionManager.js";
|
|
10
6
|
export { StateManager } from "./StateManager.js";
|
|
11
7
|
export { StyleManager } from "./StyleManager.js";
|
|
@@ -3,25 +3,19 @@ import {
|
|
|
3
3
|
BlocksChanged,
|
|
4
4
|
getBlocksChangedByTransaction,
|
|
5
5
|
} from "../../api/getBlocksChangedByTransaction.js";
|
|
6
|
-
import {
|
|
6
|
+
import { createExtension } from "../../editor/BlockNoteExtension.js";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* This plugin can filter transactions before they are applied to the editor, but with a higher-level API than `filterTransaction` from prosemirror.
|
|
10
10
|
*/
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
return "blockChange";
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
private beforeChangeCallbacks: ((context: {
|
|
11
|
+
export const BlockChangeExtension = createExtension(() => {
|
|
12
|
+
const beforeChangeCallbacks: ((context: {
|
|
17
13
|
getChanges: () => BlocksChanged<any, any, any>;
|
|
18
14
|
tr: Transaction;
|
|
19
15
|
}) => boolean | void)[] = [];
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
this.addProsemirrorPlugin(
|
|
16
|
+
return {
|
|
17
|
+
key: "blockChange",
|
|
18
|
+
prosemirrorPlugins: [
|
|
25
19
|
new Plugin({
|
|
26
20
|
key: new PluginKey("blockChange"),
|
|
27
21
|
filterTransaction: (tr) => {
|
|
@@ -29,7 +23,7 @@ export class BlockChangePlugin extends BlockNoteExtension {
|
|
|
29
23
|
| ReturnType<typeof getBlocksChangedByTransaction>
|
|
30
24
|
| undefined = undefined;
|
|
31
25
|
|
|
32
|
-
return
|
|
26
|
+
return beforeChangeCallbacks.reduce((acc, cb) => {
|
|
33
27
|
if (acc === false) {
|
|
34
28
|
// We only care that we hit a `false` result, so we can stop iterating.
|
|
35
29
|
return acc;
|
|
@@ -49,21 +43,25 @@ export class BlockChangePlugin extends BlockNoteExtension {
|
|
|
49
43
|
}, true);
|
|
50
44
|
},
|
|
51
45
|
}),
|
|
52
|
-
|
|
53
|
-
}
|
|
46
|
+
],
|
|
54
47
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Subscribe to the block change events.
|
|
50
|
+
*/
|
|
51
|
+
subscribe(
|
|
52
|
+
callback: (context: {
|
|
53
|
+
getChanges: () => BlocksChanged<any, any, any>;
|
|
54
|
+
tr: Transaction;
|
|
55
|
+
}) => boolean | void,
|
|
56
|
+
) {
|
|
57
|
+
beforeChangeCallbacks.push(callback);
|
|
62
58
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
59
|
+
return () => {
|
|
60
|
+
beforeChangeCallbacks.splice(
|
|
61
|
+
beforeChangeCallbacks.indexOf(callback),
|
|
62
|
+
1,
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
} as const;
|
|
67
|
+
});
|