@blocknote/core 0.30.1 → 0.31.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 +9 -9
- package/dist/blocknote.cjs.map +1 -1
- package/dist/blocknote.js +2754 -2230
- package/dist/blocknote.js.map +1 -1
- package/dist/{en-D4taoCs4.cjs → en-BXVKCwYt.cjs} +2 -2
- package/dist/en-BXVKCwYt.cjs.map +1 -0
- package/dist/{en-B7ycW7c8.js → en-qGo6sk9V.js} +2 -3
- package/dist/en-qGo6sk9V.js.map +1 -0
- package/dist/locales.cjs +1 -1
- package/dist/locales.cjs.map +1 -1
- package/dist/locales.js +20 -39
- package/dist/locales.js.map +1 -1
- package/dist/style.css +1 -1
- package/dist/webpack-stats.json +1 -1
- package/package.json +4 -5
- package/src/api/blockManipulation/commands/insertBlocks/insertBlocks.ts +2 -3
- package/src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.ts +1 -1
- package/src/api/blockManipulation/commands/updateBlock/__snapshots__/updateBlock.test.ts.snap +2816 -0
- package/src/api/blockManipulation/commands/updateBlock/updateBlock.test.ts +158 -0
- package/src/api/blockManipulation/commands/updateBlock/updateBlock.ts +87 -17
- package/src/api/blockManipulation/selections/selection.ts +48 -1
- package/src/api/blockManipulation/selections/{textCursorPosition/textCursorPosition.ts → textCursorPosition.ts} +7 -7
- package/src/api/getBlockInfoFromPos.ts +1 -1
- package/src/api/nodeConversions/blockToNode.ts +5 -2
- package/src/api/nodeConversions/nodeToBlock.ts +203 -8
- package/src/api/pmUtil.ts +3 -3
- package/src/blocks/CodeBlockContent/CodeBlockContent.ts +6 -6
- package/src/blocks/FileBlockContent/helpers/render/createAddFileButton.ts +1 -1
- package/src/blocks/TableBlockContent/TableBlockContent.ts +32 -2
- package/src/editor/Block.css +27 -1
- package/src/editor/BlockNoteEditor.test.ts +7 -0
- package/src/editor/BlockNoteEditor.ts +88 -37
- package/src/editor/BlockNoteExtension.ts +26 -0
- package/src/editor/BlockNoteExtensions.ts +28 -12
- package/src/editor/BlockNoteTipTapEditor.ts +23 -2
- package/src/extensions/Collaboration/CursorPlugin.ts +13 -7
- package/src/extensions/Collaboration/ForkYDocPlugin.test.ts +166 -0
- package/src/extensions/Collaboration/ForkYDocPlugin.ts +174 -0
- package/src/extensions/Collaboration/SyncPlugin.ts +7 -4
- package/src/extensions/Collaboration/UndoPlugin.ts +7 -4
- package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-editor-forked.json +30 -0
- package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-editor.json +30 -0
- package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-forked.html +1 -0
- package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap.html +1 -0
- package/src/extensions/Comments/CommentsPlugin.ts +75 -70
- package/src/extensions/FilePanel/FilePanelPlugin.ts +50 -49
- package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +56 -26
- package/src/extensions/LinkToolbar/LinkToolbarPlugin.ts +22 -21
- package/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.ts +45 -42
- package/src/extensions/Placeholder/PlaceholderPlugin.ts +111 -108
- package/src/extensions/PreviousBlockType/PreviousBlockTypePlugin.ts +179 -170
- package/src/extensions/ShowSelection/ShowSelectionPlugin.ts +22 -19
- package/src/extensions/SideMenu/SideMenuPlugin.ts +19 -18
- package/src/extensions/SuggestionMenu/SuggestionPlugin.ts +168 -168
- package/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts +4 -4
- package/src/extensions/Suggestions/SuggestionMarks.ts +175 -0
- package/src/extensions/TableHandles/TableHandlesPlugin.ts +153 -150
- package/src/i18n/locales/ar.ts +0 -1
- package/src/i18n/locales/de.ts +0 -1
- package/src/i18n/locales/en.ts +0 -1
- package/src/i18n/locales/es.ts +0 -1
- package/src/i18n/locales/fr.ts +0 -1
- package/src/i18n/locales/hr.ts +0 -1
- package/src/i18n/locales/is.ts +0 -1
- package/src/i18n/locales/it.ts +0 -1
- package/src/i18n/locales/ja.ts +0 -1
- package/src/i18n/locales/ko.ts +0 -1
- package/src/i18n/locales/nl.ts +0 -1
- package/src/i18n/locales/no.ts +0 -1
- package/src/i18n/locales/pl.ts +0 -1
- package/src/i18n/locales/pt.ts +0 -1
- package/src/i18n/locales/ru.ts +0 -1
- package/src/i18n/locales/sk.ts +0 -1
- package/src/i18n/locales/uk.ts +0 -1
- package/src/i18n/locales/vi.ts +0 -1
- package/src/i18n/locales/zh-tw.ts +0 -1
- package/src/i18n/locales/zh.ts +0 -1
- package/src/index.ts +18 -8
- package/src/pm-nodes/BlockContainer.ts +1 -1
- package/src/pm-nodes/BlockGroup.ts +1 -1
- package/src/pm-nodes/Doc.ts +1 -0
- package/types/src/api/blockManipulation/commands/insertBlocks/insertBlocks.d.ts +1 -1
- package/types/src/api/blockManipulation/commands/removeBlocks/removeBlocks.d.ts +4 -0
- package/types/src/api/blockManipulation/commands/removeBlocks/removeBlocks.test.d.ts +1 -0
- package/types/src/api/blockManipulation/commands/updateBlock/updateBlock.d.ts +3 -1
- package/types/src/api/blockManipulation/selections/selection.d.ts +10 -0
- package/types/src/api/blockManipulation/selections/textCursorPosition.d.ts +5 -0
- package/types/src/api/blockManipulation/transactions.test.d.ts +0 -0
- package/types/src/api/clipboard/clipboardExternal.test.d.ts +1 -0
- package/types/src/api/clipboard/clipboardInternal.test.d.ts +1 -0
- package/types/src/api/clipboard/testUtil.d.ts +541 -0
- package/types/src/api/exporters/html/htmlConversion.test.d.ts +1 -0
- package/types/src/api/exporters/markdown/markdownExporter.test.d.ts +1 -0
- package/types/src/api/nodeConversions/nodeConversions.test.d.ts +1 -0
- package/types/src/api/nodeConversions/nodeToBlock.d.ts +39 -2
- package/types/src/api/parsers/html/parseHTML.test.d.ts +1 -0
- package/types/src/api/parsers/markdown/parseMarkdown.test.d.ts +1 -0
- package/types/src/api/pmUtil.d.ts +3 -3
- package/types/src/api/testUtil/cases/customBlocks.d.ts +670 -0
- package/types/src/api/testUtil/cases/customInlineContent.d.ts +558 -0
- package/types/src/api/testUtil/cases/customStyles.d.ts +552 -0
- package/types/src/api/testUtil/cases/defaultSchema.d.ts +4 -0
- package/types/src/api/testUtil/index.d.ts +14 -0
- package/types/src/api/testUtil/partialBlockTestUtil.d.ts +9 -0
- package/types/src/api/testUtil/paste.d.ts +2 -0
- package/types/src/blocks/CodeBlockContent/defaultSupportedLanguages.d.ts +6 -0
- package/types/src/blocks/TableBlockContent/TableBlockContent.d.ts +9 -1
- package/types/src/editor/BlockNoteEditor.d.ts +55 -9
- package/types/src/editor/BlockNoteExtension.d.ts +9 -0
- package/types/src/editor/BlockNoteExtensions.d.ts +2 -2
- package/types/src/editor/BlockNoteTipTapEditor.d.ts +2 -2
- package/types/src/extensions/Collaboration/CursorPlugin.d.ts +3 -3
- package/types/src/extensions/Collaboration/ForkYDocPlugin.d.ts +41 -0
- package/types/src/extensions/Collaboration/ForkYDocPlugin.test.d.ts +1 -0
- package/types/src/extensions/Collaboration/SyncPlugin.d.ts +3 -3
- package/types/src/extensions/Collaboration/UndoPlugin.d.ts +3 -3
- package/types/src/extensions/Collaboration/createCollaborationExtensions.d.ts +17 -0
- package/types/src/extensions/Comments/CommentsPlugin.d.ts +2 -4
- package/types/src/extensions/FilePanel/FilePanelPlugin.d.ts +3 -4
- package/types/src/extensions/FormattingToolbar/FormattingToolbarPlugin.d.ts +5 -5
- package/types/src/extensions/LinkToolbar/LinkToolbarPlugin.d.ts +3 -4
- package/types/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.d.ts +2 -3
- package/types/src/extensions/Placeholder/PlaceholderPlugin.d.ts +2 -3
- package/types/src/extensions/PreviousBlockType/PreviousBlockTypePlugin.d.ts +2 -3
- package/types/src/extensions/ShowSelection/ShowSelectionPlugin.d.ts +2 -3
- package/types/src/extensions/SideMenu/SideMenuPlugin.d.ts +3 -4
- package/types/src/extensions/SuggestionMenu/SuggestionPlugin.d.ts +2 -4
- package/types/src/extensions/Suggestions/SuggestionMarks.d.ts +4 -0
- package/types/src/extensions/TableHandles/TableHandlesPlugin.d.ts +5 -6
- package/types/src/i18n/locales/en.d.ts +0 -1
- package/types/src/i18n/locales/sk.d.ts +0 -1
- package/types/src/index.d.ts +15 -8
- package/dist/en-B7ycW7c8.js.map +0 -1
- package/dist/en-D4taoCs4.cjs.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/src/api/blockManipulation/selections/__snapshots__/selection.test.ts.snap +0 -844
- package/src/api/blockManipulation/selections/selection.test.ts +0 -72
- package/src/api/blockManipulation/selections/textCursorPosition/__snapshots__/textCursorPosition.test.ts.snap +0 -316
- package/src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.test.ts +0 -74
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
|
|
3
|
+
import { getBlockInfo } from "../../../getBlockInfoFromPos.js";
|
|
4
|
+
import { getNodeById } from "../../../nodeUtil.js";
|
|
3
5
|
import { setupTestEnv } from "../../setupTestEnv.js";
|
|
4
6
|
import { updateBlock } from "./updateBlock.js";
|
|
5
7
|
|
|
@@ -173,6 +175,162 @@ describe("Test updateBlock", () => {
|
|
|
173
175
|
expect(getEditor().document).toMatchSnapshot();
|
|
174
176
|
});
|
|
175
177
|
|
|
178
|
+
it("Update partial (offset start)", () => {
|
|
179
|
+
const info = getBlockInfo(
|
|
180
|
+
getNodeById("heading-with-everything", getEditor().prosemirrorState.doc)!,
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
if (!info.isBlockContainer) {
|
|
184
|
+
throw new Error("heading-with-everything is not a block container");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
getEditor().transact((tr) =>
|
|
188
|
+
updateBlock(
|
|
189
|
+
tr,
|
|
190
|
+
"heading-with-everything",
|
|
191
|
+
{
|
|
192
|
+
content: [
|
|
193
|
+
{
|
|
194
|
+
type: "text",
|
|
195
|
+
text: "without styles",
|
|
196
|
+
styles: {},
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
},
|
|
200
|
+
info.blockContent.beforePos + 9,
|
|
201
|
+
),
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("Update partial (offset start + end)", () => {
|
|
208
|
+
const info = getBlockInfo(
|
|
209
|
+
getNodeById("heading-with-everything", getEditor().prosemirrorState.doc)!,
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
if (!info.isBlockContainer) {
|
|
213
|
+
throw new Error("heading-with-everything is not a block container");
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
getEditor().transact((tr) =>
|
|
217
|
+
updateBlock(
|
|
218
|
+
tr,
|
|
219
|
+
"heading-with-everything",
|
|
220
|
+
{
|
|
221
|
+
content: [
|
|
222
|
+
{
|
|
223
|
+
type: "text",
|
|
224
|
+
text: "without styles and ",
|
|
225
|
+
styles: {},
|
|
226
|
+
},
|
|
227
|
+
],
|
|
228
|
+
},
|
|
229
|
+
info.blockContent.beforePos + 9,
|
|
230
|
+
info.blockContent.beforePos + 9,
|
|
231
|
+
),
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it("Update partial (props + offset end)", () => {
|
|
238
|
+
const info = getBlockInfo(
|
|
239
|
+
getNodeById("heading-with-everything", getEditor().prosemirrorState.doc)!,
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
if (!info.isBlockContainer) {
|
|
243
|
+
throw new Error("heading-with-everything is not a block container");
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
getEditor().transact((tr) => {
|
|
247
|
+
updateBlock(
|
|
248
|
+
tr,
|
|
249
|
+
"heading-with-everything",
|
|
250
|
+
{
|
|
251
|
+
props: {
|
|
252
|
+
level: 1,
|
|
253
|
+
},
|
|
254
|
+
content: [
|
|
255
|
+
{
|
|
256
|
+
type: "text",
|
|
257
|
+
text: "Title",
|
|
258
|
+
styles: {},
|
|
259
|
+
},
|
|
260
|
+
],
|
|
261
|
+
},
|
|
262
|
+
undefined,
|
|
263
|
+
info.blockContent.beforePos + 8,
|
|
264
|
+
);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it("Update partial (table cell)", () => {
|
|
271
|
+
const info = getBlockInfo(
|
|
272
|
+
getNodeById("table-0", getEditor().prosemirrorState.doc)!,
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
if (!info.isBlockContainer) {
|
|
276
|
+
throw new Error("table-0 is not a block container");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const cell = info.blockContent.node.resolve(2);
|
|
280
|
+
|
|
281
|
+
getEditor().transact((tr) =>
|
|
282
|
+
updateBlock(
|
|
283
|
+
tr,
|
|
284
|
+
"table-0",
|
|
285
|
+
{
|
|
286
|
+
type: "table",
|
|
287
|
+
content: {
|
|
288
|
+
type: "tableContent",
|
|
289
|
+
rows: [{ cells: ["updated cell 1"] }],
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
info.blockContent.beforePos + 2,
|
|
293
|
+
info.blockContent.beforePos + 2 + cell.node().nodeSize,
|
|
294
|
+
),
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it("Update partial (table row)", () => {
|
|
301
|
+
const info = getBlockInfo(
|
|
302
|
+
getNodeById("table-0", getEditor().prosemirrorState.doc)!,
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
if (!info.isBlockContainer) {
|
|
306
|
+
throw new Error("table-0 is not a block container");
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const cell = info.blockContent.node.resolve(1);
|
|
310
|
+
|
|
311
|
+
getEditor().transact((tr) =>
|
|
312
|
+
updateBlock(
|
|
313
|
+
tr,
|
|
314
|
+
"table-0",
|
|
315
|
+
{
|
|
316
|
+
type: "table",
|
|
317
|
+
content: {
|
|
318
|
+
type: "tableContent",
|
|
319
|
+
rows: [
|
|
320
|
+
{
|
|
321
|
+
cells: ["updated cell 1", "updated cell 2", "updated cell 3"],
|
|
322
|
+
},
|
|
323
|
+
],
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
info.blockContent.beforePos + 1,
|
|
327
|
+
info.blockContent.beforePos + 1 + cell.node().nodeSize,
|
|
328
|
+
),
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
expect(getEditor().document).toMatchSnapshot();
|
|
332
|
+
});
|
|
333
|
+
|
|
176
334
|
it("Update children", () => {
|
|
177
335
|
expect(
|
|
178
336
|
getEditor().transact((tr) =>
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from "prosemirror-model";
|
|
7
7
|
import type { Transaction } from "prosemirror-state";
|
|
8
8
|
|
|
9
|
-
import { ReplaceStep } from "prosemirror-transform";
|
|
9
|
+
import { ReplaceStep, Transform } from "prosemirror-transform";
|
|
10
10
|
import type { Block, PartialBlock } from "../../../../blocks/defaultBlocks.js";
|
|
11
11
|
import type {
|
|
12
12
|
BlockIdentifier,
|
|
@@ -28,6 +28,7 @@ import { nodeToBlock } from "../../../nodeConversions/nodeToBlock.js";
|
|
|
28
28
|
import { getNodeById } from "../../../nodeUtil.js";
|
|
29
29
|
import { getPmSchema } from "../../../pmUtil.js";
|
|
30
30
|
|
|
31
|
+
// for compatibility with tiptap. TODO: remove as we want to remove dependency on tiptap command interface
|
|
31
32
|
export const updateBlockCommand = <
|
|
32
33
|
BSchema extends BlockSchema,
|
|
33
34
|
I extends InlineContentSchema,
|
|
@@ -50,18 +51,29 @@ export const updateBlockCommand = <
|
|
|
50
51
|
};
|
|
51
52
|
};
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
export function updateBlockTr<
|
|
54
55
|
BSchema extends BlockSchema,
|
|
55
56
|
I extends InlineContentSchema,
|
|
56
57
|
S extends StyleSchema,
|
|
57
58
|
>(
|
|
58
|
-
tr:
|
|
59
|
+
tr: Transform,
|
|
59
60
|
posBeforeBlock: number,
|
|
60
61
|
block: PartialBlock<BSchema, I, S>,
|
|
61
|
-
|
|
62
|
+
replaceFromPos?: number,
|
|
63
|
+
replaceToPos?: number,
|
|
64
|
+
) {
|
|
62
65
|
const blockInfo = getBlockInfoFromResolvedPos(tr.doc.resolve(posBeforeBlock));
|
|
63
66
|
|
|
64
67
|
const pmSchema = getPmSchema(tr);
|
|
68
|
+
|
|
69
|
+
if (
|
|
70
|
+
replaceFromPos !== undefined &&
|
|
71
|
+
replaceToPos !== undefined &&
|
|
72
|
+
replaceFromPos > replaceToPos
|
|
73
|
+
) {
|
|
74
|
+
throw new Error("Invalid replaceFromPos or replaceToPos");
|
|
75
|
+
}
|
|
76
|
+
|
|
65
77
|
// Adds blockGroup node with child blocks if necessary.
|
|
66
78
|
|
|
67
79
|
const oldNodeType = pmSchema.nodes[blockInfo.blockNoteType];
|
|
@@ -71,10 +83,32 @@ const updateBlockTr = <
|
|
|
71
83
|
: pmSchema.nodes["blockContainer"];
|
|
72
84
|
|
|
73
85
|
if (blockInfo.isBlockContainer && newNodeType.isInGroup("blockContent")) {
|
|
86
|
+
const replaceFromOffset =
|
|
87
|
+
replaceFromPos !== undefined &&
|
|
88
|
+
replaceFromPos > blockInfo.blockContent.beforePos &&
|
|
89
|
+
replaceFromPos < blockInfo.blockContent.afterPos
|
|
90
|
+
? replaceFromPos - blockInfo.blockContent.beforePos - 1
|
|
91
|
+
: undefined;
|
|
92
|
+
|
|
93
|
+
const replaceToOffset =
|
|
94
|
+
replaceToPos !== undefined &&
|
|
95
|
+
replaceToPos > blockInfo.blockContent.beforePos &&
|
|
96
|
+
replaceToPos < blockInfo.blockContent.afterPos
|
|
97
|
+
? replaceToPos - blockInfo.blockContent.beforePos - 1
|
|
98
|
+
: undefined;
|
|
99
|
+
|
|
74
100
|
updateChildren(block, tr, blockInfo);
|
|
75
101
|
// The code below determines the new content of the block.
|
|
76
102
|
// or "keep" to keep as-is
|
|
77
|
-
updateBlockContentNode(
|
|
103
|
+
updateBlockContentNode(
|
|
104
|
+
block,
|
|
105
|
+
tr,
|
|
106
|
+
oldNodeType,
|
|
107
|
+
newNodeType,
|
|
108
|
+
blockInfo,
|
|
109
|
+
replaceFromOffset,
|
|
110
|
+
replaceToOffset,
|
|
111
|
+
);
|
|
78
112
|
} else if (!blockInfo.isBlockContainer && newNodeType.isInGroup("bnBlock")) {
|
|
79
113
|
updateChildren(block, tr, blockInfo);
|
|
80
114
|
// old node was a bnBlock type (like column or columnList) and new block as well
|
|
@@ -109,7 +143,7 @@ const updateBlockTr = <
|
|
|
109
143
|
...blockInfo.bnBlock.node.attrs,
|
|
110
144
|
...block.props,
|
|
111
145
|
});
|
|
112
|
-
}
|
|
146
|
+
}
|
|
113
147
|
|
|
114
148
|
function updateBlockContentNode<
|
|
115
149
|
BSchema extends BlockSchema,
|
|
@@ -117,7 +151,7 @@ function updateBlockContentNode<
|
|
|
117
151
|
S extends StyleSchema,
|
|
118
152
|
>(
|
|
119
153
|
block: PartialBlock<BSchema, I, S>,
|
|
120
|
-
tr:
|
|
154
|
+
tr: Transform,
|
|
121
155
|
oldNodeType: NodeType,
|
|
122
156
|
newNodeType: NodeType,
|
|
123
157
|
blockInfo: {
|
|
@@ -126,6 +160,8 @@ function updateBlockContentNode<
|
|
|
126
160
|
| undefined;
|
|
127
161
|
blockContent: { node: PMNode; beforePos: number; afterPos: number };
|
|
128
162
|
},
|
|
163
|
+
replaceFromOffset?: number,
|
|
164
|
+
replaceToOffset?: number,
|
|
129
165
|
) {
|
|
130
166
|
const pmSchema = getPmSchema(tr);
|
|
131
167
|
let content: PMNode[] | "keep" = "keep";
|
|
@@ -172,17 +208,43 @@ function updateBlockContentNode<
|
|
|
172
208
|
// content is being replaced or not.
|
|
173
209
|
if (content === "keep") {
|
|
174
210
|
// use setNodeMarkup to only update the type and attributes
|
|
175
|
-
tr.setNodeMarkup(
|
|
176
|
-
blockInfo.blockContent.
|
|
177
|
-
block.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
211
|
+
tr.setNodeMarkup(blockInfo.blockContent.beforePos, newNodeType, {
|
|
212
|
+
...blockInfo.blockContent.node.attrs,
|
|
213
|
+
...block.props,
|
|
214
|
+
});
|
|
215
|
+
} else if (replaceFromOffset !== undefined || replaceToOffset !== undefined) {
|
|
216
|
+
// first update markup of the containing node
|
|
217
|
+
tr.setNodeMarkup(blockInfo.blockContent.beforePos, newNodeType, {
|
|
218
|
+
...blockInfo.blockContent.node.attrs,
|
|
219
|
+
...block.props,
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
const start =
|
|
223
|
+
blockInfo.blockContent.beforePos + 1 + (replaceFromOffset ?? 0);
|
|
224
|
+
const end =
|
|
225
|
+
blockInfo.blockContent.beforePos +
|
|
226
|
+
1 +
|
|
227
|
+
(replaceToOffset ?? blockInfo.blockContent.node.content.size);
|
|
228
|
+
|
|
229
|
+
// for content like table cells (where the blockcontent has nested PM nodes),
|
|
230
|
+
// we need to figure out the correct openStart and openEnd for the slice when replacing
|
|
231
|
+
|
|
232
|
+
const contentDepth = tr.doc.resolve(blockInfo.blockContent.beforePos).depth;
|
|
233
|
+
const startDepth = tr.doc.resolve(start).depth;
|
|
234
|
+
const endDepth = tr.doc.resolve(end).depth;
|
|
235
|
+
|
|
236
|
+
tr.replace(
|
|
237
|
+
start,
|
|
238
|
+
end,
|
|
239
|
+
new Slice(
|
|
240
|
+
Fragment.from(content),
|
|
241
|
+
startDepth - contentDepth - 1,
|
|
242
|
+
endDepth - contentDepth - 1,
|
|
243
|
+
),
|
|
182
244
|
);
|
|
183
245
|
} else {
|
|
184
246
|
// use replaceWith to replace the content and the block itself
|
|
185
|
-
// also
|
|
247
|
+
// also reset the selection since replacing the block content
|
|
186
248
|
// sets it to the next block.
|
|
187
249
|
tr.replaceWith(
|
|
188
250
|
blockInfo.blockContent.beforePos,
|
|
@@ -202,7 +264,7 @@ function updateChildren<
|
|
|
202
264
|
BSchema extends BlockSchema,
|
|
203
265
|
I extends InlineContentSchema,
|
|
204
266
|
S extends StyleSchema,
|
|
205
|
-
>(block: PartialBlock<BSchema, I, S>, tr:
|
|
267
|
+
>(block: PartialBlock<BSchema, I, S>, tr: Transform, blockInfo: BlockInfo) {
|
|
206
268
|
const pmSchema = getPmSchema(tr);
|
|
207
269
|
if (block.children !== undefined && block.children.length > 0) {
|
|
208
270
|
const childNodes = block.children.map((child) => {
|
|
@@ -242,6 +304,8 @@ export function updateBlock<
|
|
|
242
304
|
tr: Transaction,
|
|
243
305
|
blockToUpdate: BlockIdentifier,
|
|
244
306
|
update: PartialBlock<BSchema, I, S>,
|
|
307
|
+
replaceFromPos?: number,
|
|
308
|
+
replaceToPos?: number,
|
|
245
309
|
): Block<BSchema, I, S> {
|
|
246
310
|
const id =
|
|
247
311
|
typeof blockToUpdate === "string" ? blockToUpdate : blockToUpdate.id;
|
|
@@ -250,7 +314,13 @@ export function updateBlock<
|
|
|
250
314
|
throw new Error(`Block with ID ${id} not found`);
|
|
251
315
|
}
|
|
252
316
|
|
|
253
|
-
updateBlockTr(
|
|
317
|
+
updateBlockTr(
|
|
318
|
+
tr,
|
|
319
|
+
posInfo.posBeforeNode,
|
|
320
|
+
update,
|
|
321
|
+
replaceFromPos,
|
|
322
|
+
replaceToPos,
|
|
323
|
+
);
|
|
254
324
|
|
|
255
325
|
const blockContainerNode = tr.doc
|
|
256
326
|
.resolve(posInfo.posBeforeNode + 1) // TODO: clean?
|
|
@@ -10,7 +10,10 @@ import {
|
|
|
10
10
|
StyleSchema,
|
|
11
11
|
} from "../../../schema/index.js";
|
|
12
12
|
import { getBlockInfo, getNearestBlockPos } from "../../getBlockInfoFromPos.js";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
nodeToBlock,
|
|
15
|
+
prosemirrorSliceToSlicedBlocks,
|
|
16
|
+
} from "../../nodeConversions/nodeToBlock.js";
|
|
14
17
|
import { getNodeById } from "../../nodeUtil.js";
|
|
15
18
|
import { getBlockNoteSchema, getPmSchema } from "../../pmUtil.js";
|
|
16
19
|
|
|
@@ -216,3 +219,47 @@ export function setSelection(
|
|
|
216
219
|
// restriction that the start/end blocks must have content.
|
|
217
220
|
tr.setSelection(TextSelection.create(tr.doc, startPos, endPos));
|
|
218
221
|
}
|
|
222
|
+
|
|
223
|
+
export function getSelectionCutBlocks(tr: Transaction) {
|
|
224
|
+
// TODO: fix image node selection
|
|
225
|
+
|
|
226
|
+
const pmSchema = getPmSchema(tr);
|
|
227
|
+
let start = tr.selection.$from;
|
|
228
|
+
let end = tr.selection.$to;
|
|
229
|
+
|
|
230
|
+
// the selection moves below are used to make sure `prosemirrorSliceToSlicedBlocks` returns
|
|
231
|
+
// the correct information about whether content is cut at the start or end of a block
|
|
232
|
+
|
|
233
|
+
// if the end is at the end of a node (|</span></p>) move it forward so we include all closing tags (</span></p>|)
|
|
234
|
+
while (end.parentOffset >= end.parent.nodeSize - 2 && end.depth > 0) {
|
|
235
|
+
end = tr.doc.resolve(end.pos + 1);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// if the end is at the start of an empty node (</span></p><p>|) move it backwards so we drop empty start tags (</span></p>|)
|
|
239
|
+
while (end.parentOffset === 0 && end.depth > 0) {
|
|
240
|
+
end = tr.doc.resolve(end.pos - 1);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// if the start is at the start of a node (<p><span>|) move it backwards so we include all open tags (|<p><span>)
|
|
244
|
+
while (start.parentOffset === 0 && start.depth > 0) {
|
|
245
|
+
start = tr.doc.resolve(start.pos - 1);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// if the start is at the end of a node (|</p><p><span>|) move it forwards so we drop all closing tags (|<p><span>)
|
|
249
|
+
while (start.parentOffset >= start.parent.nodeSize - 2 && start.depth > 0) {
|
|
250
|
+
start = tr.doc.resolve(start.pos + 1);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const selectionInfo = prosemirrorSliceToSlicedBlocks(
|
|
254
|
+
tr.doc.slice(start.pos, end.pos, true),
|
|
255
|
+
pmSchema,
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
return {
|
|
259
|
+
_meta: {
|
|
260
|
+
startPos: start.pos,
|
|
261
|
+
endPos: end.pos,
|
|
262
|
+
},
|
|
263
|
+
...selectionInfo,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
@@ -4,21 +4,21 @@ import {
|
|
|
4
4
|
TextSelection,
|
|
5
5
|
type Transaction,
|
|
6
6
|
} from "prosemirror-state";
|
|
7
|
-
import type { TextCursorPosition } from "
|
|
7
|
+
import type { TextCursorPosition } from "../../../editor/cursorPositionTypes.js";
|
|
8
8
|
import type {
|
|
9
9
|
BlockIdentifier,
|
|
10
10
|
BlockSchema,
|
|
11
11
|
InlineContentSchema,
|
|
12
12
|
StyleSchema,
|
|
13
|
-
} from "
|
|
14
|
-
import { UnreachableCaseError } from "
|
|
13
|
+
} from "../../../schema/index.js";
|
|
14
|
+
import { UnreachableCaseError } from "../../../util/typescript.js";
|
|
15
15
|
import {
|
|
16
16
|
getBlockInfo,
|
|
17
17
|
getBlockInfoFromTransaction,
|
|
18
|
-
} from "
|
|
19
|
-
import { nodeToBlock } from "
|
|
20
|
-
import { getNodeById } from "
|
|
21
|
-
import { getBlockNoteSchema, getPmSchema } from "
|
|
18
|
+
} from "../../getBlockInfoFromPos.js";
|
|
19
|
+
import { nodeToBlock } from "../../nodeConversions/nodeToBlock.js";
|
|
20
|
+
import { getNodeById } from "../../nodeUtil.js";
|
|
21
|
+
import { getBlockNoteSchema, getPmSchema } from "../../pmUtil.js";
|
|
22
22
|
|
|
23
23
|
export function getTextCursorPosition<
|
|
24
24
|
BSchema extends BlockSchema,
|
|
@@ -126,7 +126,7 @@ export function getBlockInfoWithManualOffset(
|
|
|
126
126
|
): BlockInfo {
|
|
127
127
|
if (!node.type.isInGroup("bnBlock")) {
|
|
128
128
|
throw new Error(
|
|
129
|
-
`Attempted to get bnBlock node at position but found node of different type ${node.type}`,
|
|
129
|
+
`Attempted to get bnBlock node at position but found node of different type ${node.type.name}`,
|
|
130
130
|
);
|
|
131
131
|
}
|
|
132
132
|
|
|
@@ -33,7 +33,7 @@ function styledTextToNodes<T extends StyleSchema>(
|
|
|
33
33
|
): Node[] {
|
|
34
34
|
const marks: Mark[] = [];
|
|
35
35
|
|
|
36
|
-
for (const [style, value] of Object.entries(styledText.styles)) {
|
|
36
|
+
for (const [style, value] of Object.entries(styledText.styles || {})) {
|
|
37
37
|
const config = styleSchema[style];
|
|
38
38
|
if (!config) {
|
|
39
39
|
throw new Error(`style ${style} not found in styleSchema`);
|
|
@@ -51,7 +51,9 @@ function styledTextToNodes<T extends StyleSchema>(
|
|
|
51
51
|
const parseHardBreaks = !blockType || !schema.nodes[blockType].spec.code;
|
|
52
52
|
|
|
53
53
|
if (!parseHardBreaks) {
|
|
54
|
-
return
|
|
54
|
+
return styledText.text.length > 0
|
|
55
|
+
? [schema.text(styledText.text, marks)]
|
|
56
|
+
: [];
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
return (
|
|
@@ -259,6 +261,7 @@ export function tableContentToNodes<
|
|
|
259
261
|
);
|
|
260
262
|
columnNodes.push(cellNode);
|
|
261
263
|
}
|
|
264
|
+
|
|
262
265
|
const rowNode = schema.nodes["tableRow"].createChecked({}, columnNodes);
|
|
263
266
|
rowNodes.push(rowNode);
|
|
264
267
|
}
|