@blocknote/core 0.5.1 → 0.6.2
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.js +1126 -1031
- package/dist/blocknote.js.map +1 -1
- package/dist/blocknote.umd.cjs +2 -2
- package/dist/blocknote.umd.cjs.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +2 -2
- package/src/BlockNoteEditor.ts +246 -4
- package/src/BlockNoteExtensions.ts +3 -2
- package/src/api/blockManipulation/__snapshots__/blockManipulation.test.ts.snap +35 -35
- package/src/api/formatConversions/__snapshots__/formatConversions.test.ts.snap +10 -10
- package/src/api/nodeConversions/__snapshots__/nodeConversions.test.ts.snap +10 -10
- package/src/api/nodeConversions/nodeConversions.ts +11 -10
- package/src/editor.module.css +11 -2
- package/src/extensions/Blocks/api/inlineContentTypes.ts +3 -2
- package/src/extensions/Blocks/api/selectionTypes.ts +5 -0
- package/src/extensions/Blocks/nodes/Block.module.css +20 -2
- package/src/extensions/DraggableBlocks/BlockSideMenuFactoryTypes.ts +5 -6
- package/src/extensions/DraggableBlocks/DraggableBlocksExtension.ts +5 -2
- package/src/extensions/DraggableBlocks/DraggableBlocksPlugin.ts +76 -113
- package/src/extensions/FormattingToolbar/FormattingToolbarExtension.ts +6 -3
- package/src/extensions/FormattingToolbar/FormattingToolbarFactoryTypes.ts +2 -34
- package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +39 -113
- package/src/extensions/HyperlinkToolbar/HyperlinkToolbarPlugin.ts +56 -39
- package/src/extensions/UniqueID/UniqueID.ts +1 -1
- package/src/index.ts +1 -0
- package/src/shared/plugins/suggestion/SuggestionPlugin.ts +14 -2
- package/types/src/BlockNoteEditor.d.ts +81 -1
- package/types/src/extensions/Blocks/api/inlineContentTypes.d.ts +3 -2
- package/types/src/extensions/Blocks/api/selectionTypes.d.ts +4 -0
- package/types/src/extensions/DraggableBlocks/BlockSideMenuFactoryTypes.d.ts +4 -5
- package/types/src/extensions/DraggableBlocks/DraggableBlocksExtension.d.ts +3 -1
- package/types/src/extensions/DraggableBlocks/DraggableBlocksPlugin.d.ts +14 -16
- package/types/src/extensions/FormattingToolbar/FormattingToolbarExtension.d.ts +2 -0
- package/types/src/extensions/FormattingToolbar/FormattingToolbarFactoryTypes.d.ts +2 -25
- package/types/src/extensions/FormattingToolbar/FormattingToolbarPlugin.d.ts +9 -4
- package/types/src/index.d.ts +1 -0
- package/types/src/api/Editor.d.ts +0 -93
- package/types/src/extensions/SlashMenu/SlashMenuItem.d.ts +0 -24
- package/types/src/extensions/SlashMenu/defaultSlashCommands.d.ts +0 -5
|
@@ -6,8 +6,7 @@ import {
|
|
|
6
6
|
} from "@tiptap/core";
|
|
7
7
|
import { EditorState, Plugin, PluginKey } from "prosemirror-state";
|
|
8
8
|
import { EditorView } from "prosemirror-view";
|
|
9
|
-
import {
|
|
10
|
-
import { getBlockInfoFromPos } from "../Blocks/helpers/getBlockInfoFromPos";
|
|
9
|
+
import { BlockNoteEditor } from "../..";
|
|
11
10
|
import {
|
|
12
11
|
FormattingToolbar,
|
|
13
12
|
FormattingToolbarDynamicParams,
|
|
@@ -19,11 +18,12 @@ import {
|
|
|
19
18
|
// https://github.com/ueberdosis/tiptap/pull/2596/files
|
|
20
19
|
export interface FormattingToolbarPluginProps {
|
|
21
20
|
pluginKey: PluginKey;
|
|
22
|
-
|
|
21
|
+
tiptapEditor: Editor;
|
|
22
|
+
editor: BlockNoteEditor;
|
|
23
23
|
formattingToolbarFactory: FormattingToolbarFactory;
|
|
24
24
|
shouldShow?:
|
|
25
25
|
| ((props: {
|
|
26
|
-
editor:
|
|
26
|
+
editor: BlockNoteEditor;
|
|
27
27
|
view: EditorView;
|
|
28
28
|
state: EditorState;
|
|
29
29
|
oldState?: EditorState;
|
|
@@ -38,7 +38,8 @@ export type FormattingToolbarViewProps = FormattingToolbarPluginProps & {
|
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
export class FormattingToolbarView {
|
|
41
|
-
public editor:
|
|
41
|
+
public editor: BlockNoteEditor;
|
|
42
|
+
private ttEditor: Editor;
|
|
42
43
|
|
|
43
44
|
public view: EditorView;
|
|
44
45
|
|
|
@@ -50,6 +51,8 @@ export class FormattingToolbarView {
|
|
|
50
51
|
|
|
51
52
|
public toolbarIsOpen = false;
|
|
52
53
|
|
|
54
|
+
public prevWasEditable: boolean | null = null;
|
|
55
|
+
|
|
53
56
|
public shouldShow: Exclude<FormattingToolbarPluginProps["shouldShow"], null> =
|
|
54
57
|
({ view, state, from, to }) => {
|
|
55
58
|
const { doc, selection } = state;
|
|
@@ -66,11 +69,13 @@ export class FormattingToolbarView {
|
|
|
66
69
|
|
|
67
70
|
constructor({
|
|
68
71
|
editor,
|
|
72
|
+
tiptapEditor,
|
|
69
73
|
formattingToolbarFactory,
|
|
70
74
|
view,
|
|
71
75
|
shouldShow,
|
|
72
76
|
}: FormattingToolbarViewProps) {
|
|
73
77
|
this.editor = editor;
|
|
78
|
+
this.ttEditor = tiptapEditor;
|
|
74
79
|
this.view = view;
|
|
75
80
|
|
|
76
81
|
this.formattingToolbar = formattingToolbarFactory(this.getStaticParams());
|
|
@@ -83,8 +88,10 @@ export class FormattingToolbarView {
|
|
|
83
88
|
this.view.dom.addEventListener("mouseup", this.viewMouseupHandler);
|
|
84
89
|
this.view.dom.addEventListener("dragstart", this.dragstartHandler);
|
|
85
90
|
|
|
86
|
-
this.
|
|
87
|
-
this.
|
|
91
|
+
this.ttEditor.on("focus", this.focusHandler);
|
|
92
|
+
this.ttEditor.on("blur", this.blurHandler);
|
|
93
|
+
|
|
94
|
+
document.addEventListener("scroll", this.scrollHandler);
|
|
88
95
|
}
|
|
89
96
|
|
|
90
97
|
viewMousedownHandler = () => {
|
|
@@ -93,7 +100,7 @@ export class FormattingToolbarView {
|
|
|
93
100
|
|
|
94
101
|
viewMouseupHandler = () => {
|
|
95
102
|
this.preventShow = false;
|
|
96
|
-
setTimeout(() => this.update(this.
|
|
103
|
+
setTimeout(() => this.update(this.ttEditor.view));
|
|
97
104
|
};
|
|
98
105
|
|
|
99
106
|
dragstartHandler = () => {
|
|
@@ -103,7 +110,7 @@ export class FormattingToolbarView {
|
|
|
103
110
|
|
|
104
111
|
focusHandler = () => {
|
|
105
112
|
// we use `setTimeout` to make sure `selection` is already updated
|
|
106
|
-
setTimeout(() => this.update(this.
|
|
113
|
+
setTimeout(() => this.update(this.ttEditor.view));
|
|
107
114
|
};
|
|
108
115
|
|
|
109
116
|
blurHandler = ({ event }: { event: FocusEvent }) => {
|
|
@@ -128,16 +135,28 @@ export class FormattingToolbarView {
|
|
|
128
135
|
}
|
|
129
136
|
};
|
|
130
137
|
|
|
138
|
+
scrollHandler = () => {
|
|
139
|
+
if (this.toolbarIsOpen) {
|
|
140
|
+
this.formattingToolbar.render(this.getDynamicParams(), false);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
131
144
|
update(view: EditorView, oldState?: EditorState) {
|
|
132
145
|
const { state, composing } = view;
|
|
133
146
|
const { doc, selection } = state;
|
|
134
147
|
const isSame =
|
|
135
148
|
oldState && oldState.doc.eq(doc) && oldState.selection.eq(selection);
|
|
136
149
|
|
|
137
|
-
if (
|
|
150
|
+
if (
|
|
151
|
+
(this.prevWasEditable === null ||
|
|
152
|
+
this.prevWasEditable === this.editor.isEditable) &&
|
|
153
|
+
(composing || isSame)
|
|
154
|
+
) {
|
|
138
155
|
return;
|
|
139
156
|
}
|
|
140
157
|
|
|
158
|
+
this.prevWasEditable = this.editor.isEditable;
|
|
159
|
+
|
|
141
160
|
// support for CellSelections
|
|
142
161
|
const { ranges } = selection;
|
|
143
162
|
const from = Math.min(...ranges.map((range) => range.$from.pos));
|
|
@@ -154,6 +173,7 @@ export class FormattingToolbarView {
|
|
|
154
173
|
|
|
155
174
|
// Checks if menu should be shown.
|
|
156
175
|
if (
|
|
176
|
+
this.editor.isEditable &&
|
|
157
177
|
!this.toolbarIsOpen &&
|
|
158
178
|
!this.preventShow &&
|
|
159
179
|
(shouldShow || this.preventHide)
|
|
@@ -184,7 +204,7 @@ export class FormattingToolbarView {
|
|
|
184
204
|
if (
|
|
185
205
|
this.toolbarIsOpen &&
|
|
186
206
|
!this.preventHide &&
|
|
187
|
-
(!shouldShow || this.preventShow)
|
|
207
|
+
(!shouldShow || this.preventShow || !this.editor.isEditable)
|
|
188
208
|
) {
|
|
189
209
|
this.formattingToolbar.hide();
|
|
190
210
|
this.toolbarIsOpen = false;
|
|
@@ -204,12 +224,14 @@ export class FormattingToolbarView {
|
|
|
204
224
|
this.view.dom.removeEventListener("mouseup", this.viewMouseupHandler);
|
|
205
225
|
this.view.dom.removeEventListener("dragstart", this.dragstartHandler);
|
|
206
226
|
|
|
207
|
-
this.
|
|
208
|
-
this.
|
|
227
|
+
this.ttEditor.off("focus", this.focusHandler);
|
|
228
|
+
this.ttEditor.off("blur", this.blurHandler);
|
|
229
|
+
|
|
230
|
+
document.removeEventListener("scroll", this.scrollHandler);
|
|
209
231
|
}
|
|
210
232
|
|
|
211
233
|
getSelectionBoundingBox() {
|
|
212
|
-
const { state } = this.
|
|
234
|
+
const { state } = this.ttEditor.view;
|
|
213
235
|
const { selection } = state;
|
|
214
236
|
|
|
215
237
|
// support for CellSelections
|
|
@@ -218,120 +240,24 @@ export class FormattingToolbarView {
|
|
|
218
240
|
const to = Math.max(...ranges.map((range) => range.$to.pos));
|
|
219
241
|
|
|
220
242
|
if (isNodeSelection(selection)) {
|
|
221
|
-
const node = this.
|
|
243
|
+
const node = this.ttEditor.view.nodeDOM(from) as HTMLElement;
|
|
222
244
|
|
|
223
245
|
if (node) {
|
|
224
246
|
return node.getBoundingClientRect();
|
|
225
247
|
}
|
|
226
248
|
}
|
|
227
249
|
|
|
228
|
-
return posToDOMRect(this.
|
|
250
|
+
return posToDOMRect(this.ttEditor.view, from, to);
|
|
229
251
|
}
|
|
230
252
|
|
|
231
253
|
getStaticParams(): FormattingToolbarStaticParams {
|
|
232
254
|
return {
|
|
233
|
-
|
|
234
|
-
this.editor.view.focus();
|
|
235
|
-
this.editor.commands.toggleBold();
|
|
236
|
-
},
|
|
237
|
-
toggleItalic: () => {
|
|
238
|
-
this.editor.view.focus();
|
|
239
|
-
this.editor.commands.toggleItalic();
|
|
240
|
-
},
|
|
241
|
-
toggleUnderline: () => {
|
|
242
|
-
this.editor.view.focus();
|
|
243
|
-
this.editor.commands.toggleUnderline();
|
|
244
|
-
},
|
|
245
|
-
toggleStrike: () => {
|
|
246
|
-
this.editor.view.focus();
|
|
247
|
-
this.editor.commands.toggleStrike();
|
|
248
|
-
},
|
|
249
|
-
setHyperlink: (url: string, text?: string) => {
|
|
250
|
-
if (url === "") {
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
let { from, to } = this.editor.state.selection;
|
|
255
|
-
|
|
256
|
-
if (!text) {
|
|
257
|
-
text = this.editor.state.doc.textBetween(from, to);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const mark = this.editor.schema.mark("link", { href: url });
|
|
261
|
-
|
|
262
|
-
this.editor.view.dispatch(
|
|
263
|
-
this.editor.view.state.tr
|
|
264
|
-
.insertText(text, from, to)
|
|
265
|
-
.addMark(from, from + text.length, mark)
|
|
266
|
-
);
|
|
267
|
-
this.editor.view.focus();
|
|
268
|
-
},
|
|
269
|
-
setTextColor: (color: string) => {
|
|
270
|
-
this.editor.view.focus();
|
|
271
|
-
this.editor.commands.setTextColor(color);
|
|
272
|
-
},
|
|
273
|
-
setBackgroundColor: (color: string) => {
|
|
274
|
-
this.editor.view.focus();
|
|
275
|
-
this.editor.commands.setBackgroundColor(color);
|
|
276
|
-
},
|
|
277
|
-
setTextAlignment: (
|
|
278
|
-
textAlignment: "left" | "center" | "right" | "justify"
|
|
279
|
-
) => {
|
|
280
|
-
this.editor.view.focus();
|
|
281
|
-
this.editor.commands.setTextAlignment(textAlignment);
|
|
282
|
-
},
|
|
283
|
-
increaseBlockIndent: () => {
|
|
284
|
-
this.editor.view.focus();
|
|
285
|
-
this.editor.commands.sinkListItem("blockContainer");
|
|
286
|
-
},
|
|
287
|
-
decreaseBlockIndent: () => {
|
|
288
|
-
this.editor.view.focus();
|
|
289
|
-
this.editor.commands.liftListItem("blockContainer");
|
|
290
|
-
},
|
|
291
|
-
updateBlock: (updatedBlock: PartialBlock) => {
|
|
292
|
-
this.editor.view.focus();
|
|
293
|
-
this.editor.commands.BNUpdateBlock(
|
|
294
|
-
this.editor.state.selection.from,
|
|
295
|
-
updatedBlock
|
|
296
|
-
);
|
|
297
|
-
},
|
|
255
|
+
editor: this.editor,
|
|
298
256
|
};
|
|
299
257
|
}
|
|
300
258
|
|
|
301
259
|
getDynamicParams(): FormattingToolbarDynamicParams {
|
|
302
|
-
const blockInfo = getBlockInfoFromPos(
|
|
303
|
-
this.editor.state.doc,
|
|
304
|
-
this.editor.state.selection.from
|
|
305
|
-
)!;
|
|
306
|
-
|
|
307
260
|
return {
|
|
308
|
-
boldIsActive: this.editor.isActive("bold"),
|
|
309
|
-
italicIsActive: this.editor.isActive("italic"),
|
|
310
|
-
underlineIsActive: this.editor.isActive("underline"),
|
|
311
|
-
strikeIsActive: this.editor.isActive("strike"),
|
|
312
|
-
hyperlinkIsActive: this.editor.isActive("link"),
|
|
313
|
-
activeHyperlinkUrl: this.editor.getAttributes("link").href || "",
|
|
314
|
-
activeHyperlinkText: this.editor.state.doc.textBetween(
|
|
315
|
-
this.editor.state.selection.from,
|
|
316
|
-
this.editor.state.selection.to
|
|
317
|
-
),
|
|
318
|
-
textColor: this.editor.getAttributes("textColor").color || "default",
|
|
319
|
-
backgroundColor:
|
|
320
|
-
this.editor.getAttributes("backgroundColor").color || "default",
|
|
321
|
-
textAlignment:
|
|
322
|
-
this.editor.getAttributes(blockInfo.contentType).textAlignment ||
|
|
323
|
-
"left",
|
|
324
|
-
canIncreaseBlockIndent:
|
|
325
|
-
this.editor.state.doc
|
|
326
|
-
.resolve(blockInfo.startPos)
|
|
327
|
-
.index(blockInfo.depth - 1) > 0,
|
|
328
|
-
canDecreaseBlockIndent: blockInfo.depth > 2,
|
|
329
|
-
// Needs type cast as there is no way to create a type that dynamically updates based on which extensions are
|
|
330
|
-
// loaded by the editor.
|
|
331
|
-
block: {
|
|
332
|
-
type: blockInfo.contentType.name,
|
|
333
|
-
props: blockInfo.contentNode.attrs,
|
|
334
|
-
} as Block,
|
|
335
261
|
referenceRect: this.getSelectionBoundingBox(),
|
|
336
262
|
};
|
|
337
263
|
}
|
|
@@ -56,47 +56,56 @@ class HyperlinkToolbarView {
|
|
|
56
56
|
return false;
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
-
editor.view.dom.addEventListener("mouseover",
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
59
|
+
this.editor.view.dom.addEventListener("mouseover", this.mouseOverHandler);
|
|
60
|
+
document.addEventListener("scroll", this.scrollHandler);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
mouseOverHandler = (event: MouseEvent) => {
|
|
64
|
+
// Resets the hyperlink mark currently hovered by the mouse cursor.
|
|
65
|
+
this.mouseHoveredHyperlinkMark = undefined;
|
|
66
|
+
this.mouseHoveredHyperlinkMarkRange = undefined;
|
|
67
|
+
|
|
68
|
+
this.stopMenuUpdateTimer();
|
|
69
|
+
|
|
70
|
+
if (
|
|
71
|
+
event.target instanceof HTMLAnchorElement &&
|
|
72
|
+
event.target.nodeName === "A"
|
|
73
|
+
) {
|
|
74
|
+
// Finds link mark at the hovered element's position to update mouseHoveredHyperlinkMark and
|
|
75
|
+
// mouseHoveredHyperlinkMarkRange.
|
|
76
|
+
const hoveredHyperlinkElement = event.target;
|
|
77
|
+
const posInHoveredHyperlinkMark =
|
|
78
|
+
this.editor.view.posAtDOM(hoveredHyperlinkElement, 0) + 1;
|
|
79
|
+
const resolvedPosInHoveredHyperlinkMark = this.editor.state.doc.resolve(
|
|
80
|
+
posInHoveredHyperlinkMark
|
|
81
|
+
);
|
|
82
|
+
const marksAtPos = resolvedPosInHoveredHyperlinkMark.marks();
|
|
83
|
+
|
|
84
|
+
for (const mark of marksAtPos) {
|
|
85
|
+
if (mark.type.name === this.editor.schema.mark("link").type.name) {
|
|
86
|
+
this.mouseHoveredHyperlinkMark = mark;
|
|
87
|
+
this.mouseHoveredHyperlinkMarkRange =
|
|
88
|
+
getMarkRange(
|
|
89
|
+
resolvedPosInHoveredHyperlinkMark,
|
|
90
|
+
mark.type,
|
|
91
|
+
mark.attrs
|
|
92
|
+
) || undefined;
|
|
93
|
+
|
|
94
|
+
break;
|
|
92
95
|
}
|
|
93
96
|
}
|
|
97
|
+
}
|
|
94
98
|
|
|
95
|
-
|
|
99
|
+
this.startMenuUpdateTimer();
|
|
96
100
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
101
|
+
return false;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
scrollHandler = () => {
|
|
105
|
+
if (this.hyperlinkMark !== undefined) {
|
|
106
|
+
this.hyperlinkToolbar.render(this.getDynamicParams(), false);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
100
109
|
|
|
101
110
|
update() {
|
|
102
111
|
if (!this.editor.view.hasFocus()) {
|
|
@@ -145,7 +154,7 @@ class HyperlinkToolbarView {
|
|
|
145
154
|
this.hyperlinkMarkRange = this.keyboardHoveredHyperlinkMarkRange;
|
|
146
155
|
}
|
|
147
156
|
|
|
148
|
-
if (this.hyperlinkMark) {
|
|
157
|
+
if (this.hyperlinkMark && this.editor.isEditable) {
|
|
149
158
|
this.getDynamicParams();
|
|
150
159
|
|
|
151
160
|
// Shows menu.
|
|
@@ -171,7 +180,7 @@ class HyperlinkToolbarView {
|
|
|
171
180
|
}
|
|
172
181
|
|
|
173
182
|
// Hides menu.
|
|
174
|
-
if (!this.hyperlinkMark
|
|
183
|
+
if (prevHyperlinkMark && (!this.hyperlinkMark || !this.editor.isEditable)) {
|
|
175
184
|
this.hyperlinkToolbar.element?.removeEventListener(
|
|
176
185
|
"mouseleave",
|
|
177
186
|
this.startMenuUpdateTimer
|
|
@@ -187,6 +196,14 @@ class HyperlinkToolbarView {
|
|
|
187
196
|
}
|
|
188
197
|
}
|
|
189
198
|
|
|
199
|
+
destroy() {
|
|
200
|
+
this.editor.view.dom.removeEventListener(
|
|
201
|
+
"mouseover",
|
|
202
|
+
this.mouseOverHandler
|
|
203
|
+
);
|
|
204
|
+
document.removeEventListener("scroll", this.scrollHandler);
|
|
205
|
+
}
|
|
206
|
+
|
|
190
207
|
getStaticParams(): HyperlinkToolbarStaticParams {
|
|
191
208
|
return {
|
|
192
209
|
editHyperlink: (url: string, text: string) => {
|
package/src/index.ts
CHANGED
|
@@ -9,3 +9,4 @@ export * from "./extensions/SlashMenu/BaseSlashMenuItem";
|
|
|
9
9
|
export * from "./shared/EditorElement";
|
|
10
10
|
export type { SuggestionItem } from "./shared/plugins/suggestion/SuggestionItem";
|
|
11
11
|
export * from "./shared/plugins/suggestion/SuggestionsMenuFactoryTypes";
|
|
12
|
+
export * from "./extensions/Blocks/api/inlineContentTypes";
|
|
@@ -127,8 +127,16 @@ class SuggestionPluginView<T extends SuggestionItem> {
|
|
|
127
127
|
};
|
|
128
128
|
|
|
129
129
|
this.suggestionsMenu = suggestionsMenuFactory(this.getStaticParams());
|
|
130
|
+
|
|
131
|
+
document.addEventListener("scroll", this.handleScroll);
|
|
130
132
|
}
|
|
131
133
|
|
|
134
|
+
handleScroll = () => {
|
|
135
|
+
if (this.pluginKey.getState(this.editor._tiptapEditor.state).active) {
|
|
136
|
+
this.suggestionsMenu.render(this.getDynamicParams(), false);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
132
140
|
update(view: EditorView, prevState: EditorState) {
|
|
133
141
|
const prev = this.pluginKey.getState(prevState);
|
|
134
142
|
const next = this.pluginKey.getState(view.state);
|
|
@@ -147,7 +155,7 @@ class SuggestionPluginView<T extends SuggestionItem> {
|
|
|
147
155
|
|
|
148
156
|
this.pluginState = stopped ? prev : next;
|
|
149
157
|
|
|
150
|
-
if (stopped) {
|
|
158
|
+
if (stopped || !this.editor.isEditable) {
|
|
151
159
|
this.suggestionsMenu.hide();
|
|
152
160
|
|
|
153
161
|
// Listener stops focus moving to the menu on click.
|
|
@@ -160,7 +168,7 @@ class SuggestionPluginView<T extends SuggestionItem> {
|
|
|
160
168
|
this.suggestionsMenu.render(this.getDynamicParams(), false);
|
|
161
169
|
}
|
|
162
170
|
|
|
163
|
-
if (started) {
|
|
171
|
+
if (started && this.editor.isEditable) {
|
|
164
172
|
this.suggestionsMenu.render(this.getDynamicParams(), true);
|
|
165
173
|
|
|
166
174
|
// Listener stops focus moving to the menu on click.
|
|
@@ -170,6 +178,10 @@ class SuggestionPluginView<T extends SuggestionItem> {
|
|
|
170
178
|
}
|
|
171
179
|
}
|
|
172
180
|
|
|
181
|
+
destroy() {
|
|
182
|
+
document.removeEventListener("scroll", this.handleScroll);
|
|
183
|
+
}
|
|
184
|
+
|
|
173
185
|
getStaticParams(): SuggestionsMenuStaticParams<T> {
|
|
174
186
|
return {
|
|
175
187
|
itemCallback: (item: T) => this.itemCallback(item),
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { Editor as TiptapEditor } from "@tiptap/core/dist/packages/core/src/Editor";
|
|
2
2
|
import { UiFactories } from "./BlockNoteExtensions";
|
|
3
3
|
import { Block, BlockIdentifier, PartialBlock } from "./extensions/Blocks/api/blockTypes";
|
|
4
|
+
import { Styles } from "./extensions/Blocks/api/inlineContentTypes";
|
|
4
5
|
import { TextCursorPosition } from "./extensions/Blocks/api/cursorPositionTypes";
|
|
6
|
+
import { Selection } from "./extensions/Blocks/api/selectionTypes";
|
|
5
7
|
import { BaseSlashMenuItem } from "./extensions/SlashMenu";
|
|
6
8
|
export type BlockNoteEditorOptions = {
|
|
7
9
|
enableBlockNoteExtensions: boolean;
|
|
8
10
|
disableHistoryExtension: boolean;
|
|
9
11
|
/**
|
|
10
|
-
*
|
|
12
|
+
* UI element factories for creating a custom UI, including custom positioning
|
|
13
|
+
* & rendering.
|
|
11
14
|
*/
|
|
12
15
|
uiFactories: UiFactories;
|
|
13
16
|
/**
|
|
@@ -40,6 +43,13 @@ export type BlockNoteEditorOptions = {
|
|
|
40
43
|
* A callback function that runs whenever the text cursor position changes.
|
|
41
44
|
*/
|
|
42
45
|
onTextCursorPositionChange: (editor: BlockNoteEditor) => void;
|
|
46
|
+
/**
|
|
47
|
+
* Locks the editor from being editable by the user if set to `false`.
|
|
48
|
+
*/
|
|
49
|
+
editable: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* The content that should be in the editor when it's created, represented as an array of partial block objects.
|
|
52
|
+
*/
|
|
43
53
|
initialContent: PartialBlock[];
|
|
44
54
|
/**
|
|
45
55
|
* Use default BlockNote font and reset the styles of <p> <li> <h1> elements etc., that are used in BlockNote.
|
|
@@ -47,6 +57,12 @@ export type BlockNoteEditorOptions = {
|
|
|
47
57
|
* @default true
|
|
48
58
|
*/
|
|
49
59
|
defaultStyles: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Whether to use the light or dark theme.
|
|
62
|
+
*
|
|
63
|
+
* @default "light"
|
|
64
|
+
*/
|
|
65
|
+
theme: "light" | "dark";
|
|
50
66
|
_tiptapOptions: any;
|
|
51
67
|
};
|
|
52
68
|
export declare class BlockNoteEditor {
|
|
@@ -55,6 +71,7 @@ export declare class BlockNoteEditor {
|
|
|
55
71
|
};
|
|
56
72
|
private blockCache;
|
|
57
73
|
get domElement(): HTMLDivElement;
|
|
74
|
+
focus(): void;
|
|
58
75
|
constructor(options?: Partial<BlockNoteEditorOptions>);
|
|
59
76
|
/**
|
|
60
77
|
* Gets a snapshot of all top-level (non-nested) blocks in the editor.
|
|
@@ -85,6 +102,20 @@ export declare class BlockNoteEditor {
|
|
|
85
102
|
* @param placement Whether the text cursor should be placed at the start or end of the block.
|
|
86
103
|
*/
|
|
87
104
|
setTextCursorPosition(targetBlock: BlockIdentifier, placement?: "start" | "end"): void;
|
|
105
|
+
/**
|
|
106
|
+
* Gets a snapshot of the current selection.
|
|
107
|
+
*/
|
|
108
|
+
getSelection(): Selection | undefined;
|
|
109
|
+
/**
|
|
110
|
+
* Checks if the editor is currently editable, or if it's locked.
|
|
111
|
+
* @returns True if the editor is editable, false otherwise.
|
|
112
|
+
*/
|
|
113
|
+
get isEditable(): boolean;
|
|
114
|
+
/**
|
|
115
|
+
* Makes the editor editable or locks it, depending on the argument passed.
|
|
116
|
+
* @param editable True to make the editor editable, or false to lock it.
|
|
117
|
+
*/
|
|
118
|
+
set isEditable(editable: boolean);
|
|
88
119
|
/**
|
|
89
120
|
* Inserts new blocks into the editor. If a block's `id` is undefined, BlockNote generates one automatically. Throws an
|
|
90
121
|
* error if the reference block could not be found.
|
|
@@ -115,6 +146,55 @@ export declare class BlockNoteEditor {
|
|
|
115
146
|
* @param blocksToInsert An array of partial blocks to replace the old ones with.
|
|
116
147
|
*/
|
|
117
148
|
replaceBlocks(blocksToRemove: BlockIdentifier[], blocksToInsert: PartialBlock[]): void;
|
|
149
|
+
/**
|
|
150
|
+
* Gets the active text styles at the text cursor position or at the end of the current selection if it's active.
|
|
151
|
+
*/
|
|
152
|
+
getActiveStyles(): Styles;
|
|
153
|
+
/**
|
|
154
|
+
* Adds styles to the currently selected content.
|
|
155
|
+
* @param styles The styles to add.
|
|
156
|
+
*/
|
|
157
|
+
addStyles(styles: Styles): void;
|
|
158
|
+
/**
|
|
159
|
+
* Removes styles from the currently selected content.
|
|
160
|
+
* @param styles The styles to remove.
|
|
161
|
+
*/
|
|
162
|
+
removeStyles(styles: Styles): void;
|
|
163
|
+
/**
|
|
164
|
+
* Toggles styles on the currently selected content.
|
|
165
|
+
* @param styles The styles to toggle.
|
|
166
|
+
*/
|
|
167
|
+
toggleStyles(styles: Styles): void;
|
|
168
|
+
/**
|
|
169
|
+
* Gets the currently selected text.
|
|
170
|
+
*/
|
|
171
|
+
getSelectedText(): string;
|
|
172
|
+
/**
|
|
173
|
+
* Gets the URL of the last link in the current selection, or `undefined` if there are no links in the selection.
|
|
174
|
+
*/
|
|
175
|
+
getSelectedLinkUrl(): string | undefined;
|
|
176
|
+
/**
|
|
177
|
+
* Creates a new link to replace the selected content.
|
|
178
|
+
* @param url The link URL.
|
|
179
|
+
* @param text The text to display the link with.
|
|
180
|
+
*/
|
|
181
|
+
createLink(url: string, text?: string): void;
|
|
182
|
+
/**
|
|
183
|
+
* Checks if the block containing the text cursor can be nested.
|
|
184
|
+
*/
|
|
185
|
+
canNestBlock(): boolean;
|
|
186
|
+
/**
|
|
187
|
+
* Nests the block containing the text cursor into the block above it.
|
|
188
|
+
*/
|
|
189
|
+
nestBlock(): void;
|
|
190
|
+
/**
|
|
191
|
+
* Checks if the block containing the text cursor is nested.
|
|
192
|
+
*/
|
|
193
|
+
canUnnestBlock(): boolean;
|
|
194
|
+
/**
|
|
195
|
+
* Lifts the block containing the text cursor out of its parent.
|
|
196
|
+
*/
|
|
197
|
+
unnestBlock(): void;
|
|
118
198
|
/**
|
|
119
199
|
* Serializes blocks into an HTML string. To better conform to HTML standards, children of blocks which aren't list
|
|
120
200
|
* items are un-nested in the output HTML.
|
|
@@ -3,13 +3,14 @@ export type Styles = {
|
|
|
3
3
|
italic?: true;
|
|
4
4
|
underline?: true;
|
|
5
5
|
strike?: true;
|
|
6
|
+
code?: true;
|
|
6
7
|
textColor?: string;
|
|
7
8
|
backgroundColor?: string;
|
|
8
9
|
};
|
|
9
|
-
export type
|
|
10
|
+
export type ToggledStyle = {
|
|
10
11
|
[K in keyof Styles]-?: Required<Styles>[K] extends true ? K : never;
|
|
11
12
|
}[keyof Styles];
|
|
12
|
-
export type
|
|
13
|
+
export type ColorStyle = {
|
|
13
14
|
[K in keyof Styles]-?: Required<Styles>[K] extends string ? K : never;
|
|
14
15
|
}[keyof Styles];
|
|
15
16
|
export type StyledText = {
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { EditorElement, ElementFactory } from "../../shared/EditorElement";
|
|
2
|
+
import { BlockNoteEditor } from "../../BlockNoteEditor";
|
|
3
|
+
import { Block } from "../Blocks/api/blockTypes";
|
|
2
4
|
export type BlockSideMenuStaticParams = {
|
|
5
|
+
editor: BlockNoteEditor;
|
|
3
6
|
addBlock: () => void;
|
|
4
|
-
deleteBlock: () => void;
|
|
5
7
|
blockDragStart: (event: DragEvent) => void;
|
|
6
8
|
blockDragEnd: () => void;
|
|
7
9
|
freezeMenu: () => void;
|
|
8
10
|
unfreezeMenu: () => void;
|
|
9
|
-
setBlockTextColor: (color: string) => void;
|
|
10
|
-
setBlockBackgroundColor: (color: string) => void;
|
|
11
11
|
};
|
|
12
12
|
export type BlockSideMenuDynamicParams = {
|
|
13
|
-
|
|
14
|
-
blockBackgroundColor: string;
|
|
13
|
+
block: Block;
|
|
15
14
|
referenceRect: DOMRect;
|
|
16
15
|
};
|
|
17
16
|
export type BlockSideMenu = EditorElement<BlockSideMenuDynamicParams>;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Editor, Extension } from "@tiptap/core";
|
|
2
2
|
import { BlockSideMenuFactory } from "./BlockSideMenuFactoryTypes";
|
|
3
|
+
import { BlockNoteEditor } from "../../BlockNoteEditor";
|
|
3
4
|
export type DraggableBlocksOptions = {
|
|
4
|
-
|
|
5
|
+
tiptapEditor: Editor;
|
|
6
|
+
editor: BlockNoteEditor;
|
|
5
7
|
blockSideMenuFactory: BlockSideMenuFactory;
|
|
6
8
|
};
|
|
7
9
|
/**
|