@blocknote/core 0.13.4 → 0.14.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.js +526 -477
- package/dist/blocknote.js.map +1 -1
- package/dist/blocknote.umd.cjs +5 -5
- package/dist/blocknote.umd.cjs.map +1 -1
- package/dist/style.css +1 -1
- package/dist/webpack-stats.json +1 -1
- package/package.json +29 -29
- package/src/api/blockManipulation/__snapshots__/blockManipulation.test.ts.snap +98 -0
- package/src/api/blockManipulation/blockManipulation.test.ts +86 -7
- package/src/api/exporters/html/__snapshots__/customBlock/basic/external.html +1 -0
- package/src/api/exporters/html/__snapshots__/customBlock/basic/internal.html +1 -0
- package/src/api/exporters/html/__snapshots__/customParagraph/lineBreaks/external.html +1 -0
- package/src/api/exporters/html/__snapshots__/customParagraph/lineBreaks/internal.html +1 -0
- package/src/api/exporters/html/__snapshots__/paragraph/lineBreaks/external.html +1 -0
- package/src/api/exporters/html/__snapshots__/paragraph/lineBreaks/internal.html +1 -0
- package/src/api/exporters/markdown/__snapshots__/customBlock/basic/markdown.md +5 -0
- package/src/api/exporters/markdown/__snapshots__/customParagraph/lineBreaks/markdown.md +1 -0
- package/src/api/exporters/markdown/__snapshots__/paragraph/lineBreaks/markdown.md +2 -0
- package/src/api/nodeConversions/__snapshots__/nodeConversions.test.ts.snap +566 -0
- package/src/api/nodeConversions/nodeConversions.test.ts +2 -0
- package/src/api/nodeConversions/nodeConversions.ts +2 -4
- package/src/api/parsers/html/__snapshots__/paste/parse-image-in-paragraph.json +16 -0
- package/src/api/parsers/html/parseHTML.test.ts +8 -0
- package/src/api/parsers/pasteExtension.ts +5 -0
- package/src/api/testUtil/cases/customBlocks.ts +9 -0
- package/src/api/testUtil/cases/defaultSchema.ts +9 -0
- package/src/blocks/ListItemBlockContent/ListItemKeyboardShortcuts.ts +6 -6
- package/src/blocks/ParagraphBlockContent/ParagraphBlockContent.ts +7 -2
- package/src/blocks/TableBlockContent/TableBlockContent.ts +23 -1
- package/src/editor/Block.css +2 -3
- package/src/editor/BlockNoteEditor.ts +7 -6
- package/src/editor/BlockNoteExtensions.ts +10 -1
- package/src/editor/BlockNoteTipTapEditor.ts +1 -0
- package/src/extensions/FilePanel/FilePanelPlugin.ts +16 -12
- package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +12 -15
- package/src/extensions/LinkToolbar/LinkToolbarPlugin.ts +6 -2
- package/src/extensions/Placeholder/PlaceholderPlugin.ts +5 -1
- package/src/extensions/SideMenu/SideMenuPlugin.ts +157 -118
- package/src/extensions/SuggestionMenu/SuggestionPlugin.ts +5 -2
- package/src/extensions/TableHandles/TableHandlesPlugin.ts +7 -4
- package/src/i18n/locales/pt.ts +1 -1
- package/src/i18n/locales/zh.ts +1 -1
- package/src/pm-nodes/BlockContainer.ts +11 -7
- package/src/schema/blocks/createSpec.ts +2 -2
- package/src/schema/inlineContent/createSpec.ts +2 -2
- package/types/src/editor/BlockNoteEditor.d.ts +1 -1
- package/types/src/extensions/FilePanel/FilePanelPlugin.d.ts +5 -5
- package/types/src/extensions/FormattingToolbar/FormattingToolbarPlugin.d.ts +0 -1
- package/types/src/extensions/SideMenu/SideMenuPlugin.d.ts +9 -8
- package/types/src/schema/blocks/createSpec.d.ts +2 -2
- package/types/src/schema/inlineContent/createSpec.d.ts +2 -2
|
@@ -2,7 +2,7 @@ import { Editor } from "@tiptap/core";
|
|
|
2
2
|
import { getBlockInfoFromPos } from "../../api/getBlockInfoFromPos";
|
|
3
3
|
|
|
4
4
|
export const handleEnter = (editor: Editor) => {
|
|
5
|
-
const {
|
|
5
|
+
const { contentNode, contentType } = getBlockInfoFromPos(
|
|
6
6
|
editor.state.doc,
|
|
7
7
|
editor.state.selection.from
|
|
8
8
|
)!;
|
|
@@ -23,9 +23,9 @@ export const handleEnter = (editor: Editor) => {
|
|
|
23
23
|
|
|
24
24
|
return editor.commands.first(({ state, chain, commands }) => [
|
|
25
25
|
() =>
|
|
26
|
-
// Changes list item block to a
|
|
26
|
+
// Changes list item block to a paragraph block if the content is empty.
|
|
27
27
|
commands.command(() => {
|
|
28
|
-
if (
|
|
28
|
+
if (contentNode.childCount === 0) {
|
|
29
29
|
return commands.BNUpdateBlock(state.selection.from, {
|
|
30
30
|
type: "paragraph",
|
|
31
31
|
props: {},
|
|
@@ -36,10 +36,10 @@ export const handleEnter = (editor: Editor) => {
|
|
|
36
36
|
}),
|
|
37
37
|
|
|
38
38
|
() =>
|
|
39
|
-
// Splits the current block, moving content inside that's after the cursor
|
|
40
|
-
// below.
|
|
39
|
+
// Splits the current block, moving content inside that's after the cursor
|
|
40
|
+
// to a new block of the same type below.
|
|
41
41
|
commands.command(() => {
|
|
42
|
-
if (
|
|
42
|
+
if (contentNode.childCount > 0) {
|
|
43
43
|
chain()
|
|
44
44
|
.deleteSelection()
|
|
45
45
|
.BNSplitBlock(state.selection.from, true)
|
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
} from "../../schema";
|
|
5
5
|
import { createDefaultBlockDOMOutputSpec } from "../defaultBlockHelpers";
|
|
6
6
|
import { defaultProps } from "../defaultProps";
|
|
7
|
-
import { handleEnter } from "../ListItemBlockContent/ListItemKeyboardShortcuts";
|
|
8
7
|
import { getCurrentBlockContentType } from "../../api/getCurrentBlockContentType";
|
|
9
8
|
|
|
10
9
|
export const paragraphPropSchema = {
|
|
@@ -18,7 +17,6 @@ export const ParagraphBlockContent = createStronglyTypedTiptapNode({
|
|
|
18
17
|
|
|
19
18
|
addKeyboardShortcuts() {
|
|
20
19
|
return {
|
|
21
|
-
Enter: () => handleEnter(this.editor),
|
|
22
20
|
"Mod-Alt-0": () => {
|
|
23
21
|
if (getCurrentBlockContentType(this.editor) !== "inline*") {
|
|
24
22
|
return true;
|
|
@@ -41,6 +39,13 @@ export const ParagraphBlockContent = createStronglyTypedTiptapNode({
|
|
|
41
39
|
{
|
|
42
40
|
tag: "p",
|
|
43
41
|
priority: 200,
|
|
42
|
+
getAttrs: (element) => {
|
|
43
|
+
if (typeof element === "string" || !element.textContent?.trim()) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return {};
|
|
48
|
+
},
|
|
44
49
|
node: "paragraph",
|
|
45
50
|
},
|
|
46
51
|
];
|
|
@@ -45,7 +45,29 @@ const TableParagraph = Node.create({
|
|
|
45
45
|
content: "inline*",
|
|
46
46
|
|
|
47
47
|
parseHTML() {
|
|
48
|
-
return [
|
|
48
|
+
return [
|
|
49
|
+
{ tag: "td" },
|
|
50
|
+
{
|
|
51
|
+
tag: "p",
|
|
52
|
+
getAttrs: (element) => {
|
|
53
|
+
if (typeof element === "string" || !element.textContent) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const parent = element.parentElement;
|
|
58
|
+
|
|
59
|
+
if (parent === null) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (parent.tagName === "TD") {
|
|
64
|
+
return {};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return false;
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
];
|
|
49
71
|
},
|
|
50
72
|
|
|
51
73
|
renderHTML({ HTMLAttributes }) {
|
package/src/editor/Block.css
CHANGED
|
@@ -279,7 +279,6 @@ NESTED BLOCKS
|
|
|
279
279
|
background-color: rgb(242, 241, 238);
|
|
280
280
|
border-radius: 4px;
|
|
281
281
|
color: rgb(125, 121, 122);
|
|
282
|
-
cursor: pointer;
|
|
283
282
|
display: flex;
|
|
284
283
|
flex-direction: row;
|
|
285
284
|
gap: 10px;
|
|
@@ -287,7 +286,7 @@ NESTED BLOCKS
|
|
|
287
286
|
width: 100%;
|
|
288
287
|
}
|
|
289
288
|
|
|
290
|
-
[data-file-block] .bn-add-file-button:hover {
|
|
289
|
+
.bn-editor[contenteditable="true"] [data-file-block] .bn-add-file-button:hover {
|
|
291
290
|
background-color: rgb(225, 225, 225);
|
|
292
291
|
}
|
|
293
292
|
|
|
@@ -363,7 +362,7 @@ NESTED BLOCKS
|
|
|
363
362
|
}
|
|
364
363
|
|
|
365
364
|
/* PLACEHOLDERS*/
|
|
366
|
-
.bn-inline-content:has(> .ProseMirror-trailingBreak):before {
|
|
365
|
+
.bn-inline-content:has(> .ProseMirror-trailingBreak:only-child):before {
|
|
367
366
|
/*float: left; */
|
|
368
367
|
pointer-events: none;
|
|
369
368
|
height: 0;
|
|
@@ -194,11 +194,7 @@ export class BlockNoteEditor<
|
|
|
194
194
|
ISchema,
|
|
195
195
|
SSchema
|
|
196
196
|
>;
|
|
197
|
-
public readonly filePanel?: FilePanelProsemirrorPlugin<
|
|
198
|
-
BSchema,
|
|
199
|
-
ISchema,
|
|
200
|
-
SSchema
|
|
201
|
-
>;
|
|
197
|
+
public readonly filePanel?: FilePanelProsemirrorPlugin<ISchema, SSchema>;
|
|
202
198
|
public readonly tableHandles?: TableHandlesProsemirrorPlugin<
|
|
203
199
|
ISchema,
|
|
204
200
|
SSchema
|
|
@@ -307,6 +303,7 @@ export class BlockNoteEditor<
|
|
|
307
303
|
this.resolveFileUrl = newOptions.resolveFileUrl || (async (url) => url);
|
|
308
304
|
|
|
309
305
|
if (newOptions.collaboration && newOptions.initialContent) {
|
|
306
|
+
// eslint-disable-next-line no-console
|
|
310
307
|
console.warn(
|
|
311
308
|
"When using Collaboration, initialContent might cause conflicts, because changes should come from the collaboration provider"
|
|
312
309
|
);
|
|
@@ -777,7 +774,11 @@ export class BlockNoteEditor<
|
|
|
777
774
|
for (const mark of marks) {
|
|
778
775
|
const config = this.schema.styleSchema[mark.type.name];
|
|
779
776
|
if (!config) {
|
|
780
|
-
|
|
777
|
+
if (mark.type.name !== "link") {
|
|
778
|
+
// eslint-disable-next-line no-console
|
|
779
|
+
console.warn("mark not found in styleschema", mark.type.name);
|
|
780
|
+
}
|
|
781
|
+
|
|
781
782
|
continue;
|
|
782
783
|
}
|
|
783
784
|
if (config.propSchema === "boolean") {
|
|
@@ -75,7 +75,16 @@ export const getBlockNoteExtensions = <
|
|
|
75
75
|
Text,
|
|
76
76
|
|
|
77
77
|
// marks:
|
|
78
|
-
Link
|
|
78
|
+
Link.extend({
|
|
79
|
+
addKeyboardShortcuts() {
|
|
80
|
+
return {
|
|
81
|
+
"Mod-k": () => {
|
|
82
|
+
this.editor.commands.toggleLink({ href: "" });
|
|
83
|
+
return true;
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
},
|
|
87
|
+
}),
|
|
79
88
|
...Object.values(opts.styleSpecs).map((styleSpec) => {
|
|
80
89
|
return styleSpec.implementation.mark;
|
|
81
90
|
}),
|
|
@@ -87,6 +87,7 @@ export class BlockNoteTipTapEditor extends TiptapEditor {
|
|
|
87
87
|
this.options.parseOptions
|
|
88
88
|
);
|
|
89
89
|
} catch (e) {
|
|
90
|
+
// eslint-disable-next-line no-console
|
|
90
91
|
console.error(
|
|
91
92
|
"Error creating document from blocks passed as `initialContent`. Caused by exception: ",
|
|
92
93
|
e
|
|
@@ -5,7 +5,6 @@ import type { BlockNoteEditor } from "../../editor/BlockNoteEditor";
|
|
|
5
5
|
import { UiElementPosition } from "../../extensions-shared/UiElementPosition";
|
|
6
6
|
import type {
|
|
7
7
|
BlockFromConfig,
|
|
8
|
-
BlockSchema,
|
|
9
8
|
FileBlockConfig,
|
|
10
9
|
InlineContentSchema,
|
|
11
10
|
StyleSchema,
|
|
@@ -26,9 +25,12 @@ export class FilePanelView<I extends InlineContentSchema, S extends StyleSchema>
|
|
|
26
25
|
public state?: FilePanelState<I, S>;
|
|
27
26
|
public emitUpdate: () => void;
|
|
28
27
|
|
|
29
|
-
public prevWasEditable: boolean | null = null;
|
|
30
|
-
|
|
31
28
|
constructor(
|
|
29
|
+
private readonly editor: BlockNoteEditor<
|
|
30
|
+
Record<string, FileBlockConfig>,
|
|
31
|
+
I,
|
|
32
|
+
S
|
|
33
|
+
>,
|
|
32
34
|
private readonly pluginKey: PluginKey,
|
|
33
35
|
private readonly pmView: EditorView,
|
|
34
36
|
emitUpdate: (state: FilePanelState<I, S>) => void
|
|
@@ -42,10 +44,12 @@ export class FilePanelView<I extends InlineContentSchema, S extends StyleSchema>
|
|
|
42
44
|
};
|
|
43
45
|
|
|
44
46
|
pmView.dom.addEventListener("mousedown", this.mouseDownHandler);
|
|
45
|
-
|
|
46
47
|
pmView.dom.addEventListener("dragstart", this.dragstartHandler);
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
// Setting capture=true ensures that any parent container of the editor that
|
|
50
|
+
// gets scrolled will trigger the scroll event. Scroll events do not bubble
|
|
51
|
+
// and so won't propagate to the document by default.
|
|
52
|
+
document.addEventListener("scroll", this.scrollHandler, true);
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
mouseDownHandler = () => {
|
|
@@ -79,7 +83,7 @@ export class FilePanelView<I extends InlineContentSchema, S extends StyleSchema>
|
|
|
79
83
|
block: BlockFromConfig<FileBlockConfig, I, S>;
|
|
80
84
|
} = this.pluginKey.getState(view.state);
|
|
81
85
|
|
|
82
|
-
if (!this.state?.show && pluginState.block) {
|
|
86
|
+
if (!this.state?.show && pluginState.block && this.editor.isEditable) {
|
|
83
87
|
const blockElement = document.querySelector(
|
|
84
88
|
`[data-node-type="blockContainer"][data-id="${pluginState.block.id}"]`
|
|
85
89
|
)!;
|
|
@@ -97,7 +101,8 @@ export class FilePanelView<I extends InlineContentSchema, S extends StyleSchema>
|
|
|
97
101
|
|
|
98
102
|
if (
|
|
99
103
|
!view.state.selection.eq(prevState.selection) ||
|
|
100
|
-
!view.state.doc.eq(prevState.doc)
|
|
104
|
+
!view.state.doc.eq(prevState.doc) ||
|
|
105
|
+
!this.editor.isEditable
|
|
101
106
|
) {
|
|
102
107
|
if (this.state?.show) {
|
|
103
108
|
this.state.show = false;
|
|
@@ -119,29 +124,28 @@ export class FilePanelView<I extends InlineContentSchema, S extends StyleSchema>
|
|
|
119
124
|
|
|
120
125
|
this.pmView.dom.removeEventListener("dragstart", this.dragstartHandler);
|
|
121
126
|
|
|
122
|
-
document.removeEventListener("scroll", this.scrollHandler);
|
|
127
|
+
document.removeEventListener("scroll", this.scrollHandler, true);
|
|
123
128
|
}
|
|
124
129
|
}
|
|
125
130
|
|
|
126
131
|
const filePanelPluginKey = new PluginKey("FilePanelPlugin");
|
|
127
132
|
|
|
128
133
|
export class FilePanelProsemirrorPlugin<
|
|
129
|
-
B extends BlockSchema,
|
|
130
134
|
I extends InlineContentSchema,
|
|
131
135
|
S extends StyleSchema
|
|
132
136
|
> extends EventEmitter<any> {
|
|
133
137
|
private view: FilePanelView<I, S> | undefined;
|
|
134
138
|
public readonly plugin: Plugin;
|
|
135
139
|
|
|
136
|
-
constructor(
|
|
140
|
+
constructor(editor: BlockNoteEditor<Record<string, FileBlockConfig>, I, S>) {
|
|
137
141
|
super();
|
|
138
142
|
this.plugin = new Plugin<{
|
|
139
143
|
block: BlockFromConfig<FileBlockConfig, I, S> | undefined;
|
|
140
144
|
}>({
|
|
141
145
|
key: filePanelPluginKey,
|
|
142
146
|
view: (editorView) => {
|
|
143
|
-
this.view = new FilePanelView(
|
|
144
|
-
|
|
147
|
+
this.view = new FilePanelView<I, S>(
|
|
148
|
+
editor,
|
|
145
149
|
filePanelPluginKey,
|
|
146
150
|
editorView,
|
|
147
151
|
(state) => {
|
|
@@ -15,7 +15,6 @@ export class FormattingToolbarView implements PluginView {
|
|
|
15
15
|
|
|
16
16
|
public preventHide = false;
|
|
17
17
|
public preventShow = false;
|
|
18
|
-
public prevWasEditable: boolean | null = null;
|
|
19
18
|
|
|
20
19
|
public shouldShow: (props: {
|
|
21
20
|
view: EditorView;
|
|
@@ -60,7 +59,10 @@ export class FormattingToolbarView implements PluginView {
|
|
|
60
59
|
pmView.dom.addEventListener("dragstart", this.dragHandler);
|
|
61
60
|
pmView.dom.addEventListener("dragover", this.dragHandler);
|
|
62
61
|
|
|
63
|
-
|
|
62
|
+
// Setting capture=true ensures that any parent container of the editor that
|
|
63
|
+
// gets scrolled will trigger the scroll event. Scroll events do not bubble
|
|
64
|
+
// and so won't propagate to the document by default.
|
|
65
|
+
document.addEventListener("scroll", this.scrollHandler, true);
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
viewMousedownHandler = () => {
|
|
@@ -93,16 +95,10 @@ export class FormattingToolbarView implements PluginView {
|
|
|
93
95
|
const isSame =
|
|
94
96
|
oldState && oldState.doc.eq(doc) && oldState.selection.eq(selection);
|
|
95
97
|
|
|
96
|
-
if (
|
|
97
|
-
(this.prevWasEditable === null ||
|
|
98
|
-
this.prevWasEditable === this.editor.isEditable) &&
|
|
99
|
-
(composing || isSame)
|
|
100
|
-
) {
|
|
98
|
+
if (composing || isSame) {
|
|
101
99
|
return;
|
|
102
100
|
}
|
|
103
101
|
|
|
104
|
-
this.prevWasEditable = this.editor.isEditable;
|
|
105
|
-
|
|
106
102
|
// support for CellSelections
|
|
107
103
|
const { ranges } = selection;
|
|
108
104
|
const from = Math.min(...ranges.map((range) => range.$from.pos));
|
|
@@ -116,11 +112,12 @@ export class FormattingToolbarView implements PluginView {
|
|
|
116
112
|
});
|
|
117
113
|
|
|
118
114
|
// Checks if menu should be shown/updated.
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
115
|
+
if (!this.preventShow && (shouldShow || this.preventHide)) {
|
|
116
|
+
// Unlike other UI elements, we don't prevent the formatting toolbar from
|
|
117
|
+
// showing when the editor is not editable. This is because some buttons,
|
|
118
|
+
// e.g. the download file button, should still be accessible. Therefore,
|
|
119
|
+
// logic for hiding when the editor is non-editable is handled
|
|
120
|
+
// individually in each button.
|
|
124
121
|
this.state = {
|
|
125
122
|
show: true,
|
|
126
123
|
referencePos: this.getSelectionBoundingBox(),
|
|
@@ -150,7 +147,7 @@ export class FormattingToolbarView implements PluginView {
|
|
|
150
147
|
this.pmView.dom.removeEventListener("dragstart", this.dragHandler);
|
|
151
148
|
this.pmView.dom.removeEventListener("dragover", this.dragHandler);
|
|
152
149
|
|
|
153
|
-
document.removeEventListener("scroll", this.scrollHandler);
|
|
150
|
+
document.removeEventListener("scroll", this.scrollHandler, true);
|
|
154
151
|
}
|
|
155
152
|
|
|
156
153
|
closeMenu = () => {
|
|
@@ -62,7 +62,11 @@ class LinkToolbarView implements PluginView {
|
|
|
62
62
|
|
|
63
63
|
this.pmView.dom.addEventListener("mouseover", this.mouseOverHandler);
|
|
64
64
|
document.addEventListener("click", this.clickHandler, true);
|
|
65
|
-
|
|
65
|
+
|
|
66
|
+
// Setting capture=true ensures that any parent container of the editor that
|
|
67
|
+
// gets scrolled will trigger the scroll event. Scroll events do not bubble
|
|
68
|
+
// and so won't propagate to the document by default.
|
|
69
|
+
document.addEventListener("scroll", this.scrollHandler, true);
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
mouseOverHandler = (event: MouseEvent) => {
|
|
@@ -267,7 +271,7 @@ class LinkToolbarView implements PluginView {
|
|
|
267
271
|
|
|
268
272
|
destroy() {
|
|
269
273
|
this.pmView.dom.removeEventListener("mouseover", this.mouseOverHandler);
|
|
270
|
-
document.removeEventListener("scroll", this.scrollHandler);
|
|
274
|
+
document.removeEventListener("scroll", this.scrollHandler, true);
|
|
271
275
|
document.removeEventListener("click", this.clickHandler, true);
|
|
272
276
|
}
|
|
273
277
|
}
|
|
@@ -12,11 +12,15 @@ export const PlaceholderPlugin = (
|
|
|
12
12
|
key: PLUGIN_KEY,
|
|
13
13
|
view: () => {
|
|
14
14
|
const styleEl = document.createElement("style");
|
|
15
|
+
const nonce = editor._tiptapEditor.options.injectNonce;
|
|
16
|
+
if (nonce) {
|
|
17
|
+
styleEl.setAttribute("nonce", nonce);
|
|
18
|
+
}
|
|
15
19
|
document.head.appendChild(styleEl);
|
|
16
20
|
const styleSheet = styleEl.sheet!;
|
|
17
21
|
|
|
18
22
|
const getBaseSelector = (additionalSelectors = "") =>
|
|
19
|
-
`.bn-block-content${additionalSelectors} .bn-inline-content:has(> .ProseMirror-trailingBreak):before`;
|
|
23
|
+
`.bn-block-content${additionalSelectors} .bn-inline-content:has(> .ProseMirror-trailingBreak:only-child):before`;
|
|
20
24
|
|
|
21
25
|
const getSelector = (
|
|
22
26
|
blockType: string | "default",
|