@blocknote/core 0.19.1 → 0.20.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 +1791 -1483
- package/dist/blocknote.js.map +1 -1
- package/dist/blocknote.umd.cjs +6 -6
- package/dist/blocknote.umd.cjs.map +1 -1
- package/dist/src/api/blockManipulation/commands/insertBlocks/insertBlocks.js +6 -3
- package/dist/src/api/blockManipulation/commands/insertBlocks/insertBlocks.js.map +1 -1
- package/dist/src/api/blockManipulation/commands/moveBlocks/moveBlocks.js +219 -0
- package/dist/src/api/blockManipulation/commands/moveBlocks/moveBlocks.js.map +1 -0
- package/dist/src/api/blockManipulation/commands/moveBlocks/moveBlocks.test.js +175 -0
- package/dist/src/api/blockManipulation/commands/moveBlocks/moveBlocks.test.js.map +1 -0
- package/dist/src/api/blockManipulation/commands/splitBlock/splitBlock.test.js +3 -0
- package/dist/src/api/blockManipulation/commands/splitBlock/splitBlock.test.js.map +1 -1
- package/dist/src/api/blockManipulation/commands/updateBlock/updateBlock.js +6 -3
- package/dist/src/api/blockManipulation/commands/updateBlock/updateBlock.js.map +1 -1
- package/dist/src/api/blockManipulation/getBlock/getBlock.js +56 -0
- package/dist/src/api/blockManipulation/getBlock/getBlock.js.map +1 -0
- package/dist/src/api/blockManipulation/selections/selection.js +149 -0
- package/dist/src/api/blockManipulation/selections/selection.js.map +1 -0
- package/dist/src/api/blockManipulation/selections/selection.test.js +39 -0
- package/dist/src/api/blockManipulation/selections/selection.test.js.map +1 -0
- package/dist/src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.js +3 -0
- package/dist/src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.js.map +1 -1
- package/dist/src/api/clipboard/fromClipboard/handleVSCodePaste.js +3 -3
- package/dist/src/api/clipboard/fromClipboard/handleVSCodePaste.js.map +1 -1
- package/dist/src/api/nodeUtil.js +1 -1
- package/dist/src/api/nodeUtil.js.map +1 -1
- package/dist/src/blocks/CodeBlockContent/CodeBlockContent.js +15 -7
- package/dist/src/blocks/CodeBlockContent/CodeBlockContent.js.map +1 -1
- package/dist/src/blocks/CodeBlockContent/defaultSupportedLanguages.js +38 -18
- package/dist/src/blocks/CodeBlockContent/defaultSupportedLanguages.js.map +1 -1
- package/dist/src/blocks/TableBlockContent/TableExtension.js +8 -1
- package/dist/src/blocks/TableBlockContent/TableExtension.js.map +1 -1
- package/dist/src/editor/BlockNoteEditor.js +59 -57
- package/dist/src/editor/BlockNoteEditor.js.map +1 -1
- package/dist/src/editor/BlockNoteExtensions.js +2 -1
- package/dist/src/editor/BlockNoteExtensions.js.map +1 -1
- package/dist/src/extensions/FormattingToolbar/FormattingToolbarPlugin.js +4 -2
- package/dist/src/extensions/FormattingToolbar/FormattingToolbarPlugin.js.map +1 -1
- package/dist/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.js +10 -8
- package/dist/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.js.map +1 -1
- package/dist/src/extensions/LinkToolbar/LinkToolbarPlugin.js +7 -3
- package/dist/src/extensions/LinkToolbar/LinkToolbarPlugin.js.map +1 -1
- package/dist/src/extensions/Placeholder/PlaceholderPlugin.js +13 -7
- package/dist/src/extensions/Placeholder/PlaceholderPlugin.js.map +1 -1
- package/dist/src/extensions/SideMenu/SideMenuPlugin.js +5 -1
- package/dist/src/extensions/SideMenu/SideMenuPlugin.js.map +1 -1
- package/dist/src/extensions/SideMenu/dragging.js +5 -1
- package/dist/src/extensions/SideMenu/dragging.js.map +1 -1
- package/dist/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.js +0 -3
- package/dist/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.js.map +1 -1
- package/dist/src/extensions/TableHandles/TableHandlesPlugin.js +25 -8
- package/dist/src/extensions/TableHandles/TableHandlesPlugin.js.map +1 -1
- package/dist/src/i18n/locales/ru.js +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/style.css +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/webpack-stats.json +1 -1
- package/package.json +3 -3
- package/src/api/blockManipulation/commands/insertBlocks/insertBlocks.ts +6 -6
- package/src/api/blockManipulation/commands/moveBlocks/__snapshots__/moveBlocks.test.ts.snap +9506 -0
- package/src/api/blockManipulation/commands/moveBlocks/moveBlocks.test.ts +295 -0
- package/src/api/blockManipulation/commands/moveBlocks/moveBlocks.ts +338 -0
- package/src/api/blockManipulation/commands/splitBlock/splitBlock.test.ts +4 -0
- package/src/api/blockManipulation/commands/updateBlock/updateBlock.ts +11 -3
- package/src/api/blockManipulation/getBlock/getBlock.ts +141 -0
- package/src/api/blockManipulation/selections/__snapshots__/selection.test.ts.snap +660 -0
- package/src/api/blockManipulation/selections/selection.test.ts +56 -0
- package/src/api/blockManipulation/selections/selection.ts +244 -0
- package/src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.ts +4 -0
- package/src/api/clipboard/fromClipboard/handleVSCodePaste.ts +4 -4
- package/src/api/nodeUtil.ts +2 -2
- package/src/blocks/CodeBlockContent/CodeBlockContent.ts +18 -8
- package/src/blocks/CodeBlockContent/defaultSupportedLanguages.ts +38 -18
- package/src/blocks/TableBlockContent/TableExtension.ts +12 -1
- package/src/editor/Block.css +3 -0
- package/src/editor/BlockNoteEditor.ts +93 -85
- package/src/editor/BlockNoteExtensions.ts +3 -1
- package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +4 -2
- package/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts +11 -8
- package/src/extensions/LinkToolbar/LinkToolbarPlugin.ts +11 -4
- package/src/extensions/Placeholder/PlaceholderPlugin.ts +23 -15
- package/src/extensions/SideMenu/SideMenuPlugin.ts +5 -1
- package/src/extensions/SideMenu/dragging.ts +5 -1
- package/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts +0 -5
- package/src/extensions/TableHandles/TableHandlesPlugin.ts +34 -9
- package/src/i18n/locales/ru.ts +1 -1
- package/src/index.ts +1 -0
- package/types/src/api/blockManipulation/commands/moveBlocks/moveBlocks.d.ts +15 -0
- package/types/src/api/blockManipulation/getBlock/getBlock.d.ts +7 -0
- package/types/src/api/blockManipulation/selections/selection.d.ts +5 -0
- package/types/src/api/blockManipulation/selections/selection.test.d.ts +1 -0
- package/types/src/api/nodeUtil.d.ts +1 -1
- package/types/src/editor/BlockNoteEditor.d.ts +54 -10
- package/types/src/editor/BlockNoteExtensions.d.ts +1 -0
- package/types/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.d.ts +1 -0
- package/types/src/extensions/SideMenu/SideMenuPlugin.d.ts +1 -1
- package/types/src/index.d.ts +1 -0
- package/types/src/pm-nodes/BlockContainer.d.ts +2 -2
- package/types/src/pm-nodes/BlockGroup.d.ts +2 -2
- package/dist/src/api/blockManipulation/commands/moveBlock/moveBlock.js +0 -116
- package/dist/src/api/blockManipulation/commands/moveBlock/moveBlock.js.map +0 -1
- package/dist/src/api/blockManipulation/commands/moveBlock/moveBlock.test.js +0 -110
- package/dist/src/api/blockManipulation/commands/moveBlock/moveBlock.test.js.map +0 -1
- package/src/api/blockManipulation/commands/moveBlock/__snapshots__/moveBlock.test.ts.snap +0 -3799
- package/src/api/blockManipulation/commands/moveBlock/moveBlock.test.ts +0 -196
- package/src/api/blockManipulation/commands/moveBlock/moveBlock.ts +0 -176
- package/types/src/api/blockManipulation/commands/moveBlock/moveBlock.d.ts +0 -5
- /package/types/src/api/blockManipulation/commands/{moveBlock/moveBlock.test.d.ts → moveBlocks/moveBlocks.test.d.ts} +0 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { TextSelection } from "prosemirror-state";
|
|
2
|
+
import { TableMap } from "prosemirror-tables";
|
|
3
|
+
|
|
4
|
+
import { Block } from "../../../blocks/defaultBlocks.js";
|
|
5
|
+
import type { BlockNoteEditor } from "../../../editor/BlockNoteEditor";
|
|
6
|
+
import { Selection } from "../../../editor/selectionTypes.js";
|
|
7
|
+
import {
|
|
8
|
+
BlockIdentifier,
|
|
9
|
+
BlockSchema,
|
|
10
|
+
InlineContentSchema,
|
|
11
|
+
StyleSchema,
|
|
12
|
+
} from "../../../schema/index.js";
|
|
13
|
+
import { getBlockInfo, getNearestBlockPos } from "../../getBlockInfoFromPos.js";
|
|
14
|
+
import { nodeToBlock } from "../../nodeConversions/nodeToBlock.js";
|
|
15
|
+
import { getNodeById } from "../../nodeUtil.js";
|
|
16
|
+
|
|
17
|
+
export function getSelection<
|
|
18
|
+
BSchema extends BlockSchema,
|
|
19
|
+
I extends InlineContentSchema,
|
|
20
|
+
S extends StyleSchema
|
|
21
|
+
>(
|
|
22
|
+
editor: BlockNoteEditor<BSchema, I, S>
|
|
23
|
+
): Selection<BSchema, I, S> | undefined {
|
|
24
|
+
const state = editor._tiptapEditor.state;
|
|
25
|
+
|
|
26
|
+
const $startBlockBeforePos = state.doc.resolve(
|
|
27
|
+
getNearestBlockPos(state.doc, state.selection.from).posBeforeNode
|
|
28
|
+
);
|
|
29
|
+
const $endBlockBeforePos = state.doc.resolve(
|
|
30
|
+
getNearestBlockPos(state.doc, state.selection.to).posBeforeNode
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
// Return undefined if anchor and head are in the same block.
|
|
34
|
+
if ($startBlockBeforePos.pos === $endBlockBeforePos.pos) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Converts the node at the given index and depth around `$startBlockBeforePos`
|
|
39
|
+
// to a block. Used to get blocks at given indices at the shared depth and
|
|
40
|
+
// at the depth of `$startBlockBeforePos`.
|
|
41
|
+
const indexToBlock = (
|
|
42
|
+
index: number,
|
|
43
|
+
depth?: number
|
|
44
|
+
): Block<BSchema, I, S> => {
|
|
45
|
+
const pos = $startBlockBeforePos.posAtIndex(index, depth);
|
|
46
|
+
const node = state.doc.resolve(pos).nodeAfter;
|
|
47
|
+
|
|
48
|
+
if (!node) {
|
|
49
|
+
throw new Error(
|
|
50
|
+
`Error getting selection - node not found at position ${pos}`
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return nodeToBlock(
|
|
55
|
+
node,
|
|
56
|
+
editor.schema.blockSchema,
|
|
57
|
+
editor.schema.inlineContentSchema,
|
|
58
|
+
editor.schema.styleSchema,
|
|
59
|
+
editor.blockCache
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const blocks: Block<BSchema, I, S>[] = [];
|
|
64
|
+
// Minimum depth at which the blocks share a common ancestor.
|
|
65
|
+
const sharedDepth = $startBlockBeforePos.sharedDepth($endBlockBeforePos.pos);
|
|
66
|
+
const startIndex = $startBlockBeforePos.index(sharedDepth);
|
|
67
|
+
const endIndex = $endBlockBeforePos.index(sharedDepth);
|
|
68
|
+
|
|
69
|
+
// In most cases, we want to return the blocks spanned by the selection at the
|
|
70
|
+
// shared depth. However, when the block in which the selection starts is at a
|
|
71
|
+
// higher depth than the shared depth, we omit the first block at the shared
|
|
72
|
+
// depth. Instead, we include the first block at its depth, and any blocks at
|
|
73
|
+
// a higher index up to the shared depth. The following example illustrates
|
|
74
|
+
// this:
|
|
75
|
+
// - id-0
|
|
76
|
+
// - id-1
|
|
77
|
+
// - >|id-2
|
|
78
|
+
// - id-3
|
|
79
|
+
// - id-4
|
|
80
|
+
// - id-5
|
|
81
|
+
// - id-6
|
|
82
|
+
// - id-7
|
|
83
|
+
// - id-8
|
|
84
|
+
// - id-9|<
|
|
85
|
+
// - id-10
|
|
86
|
+
// Here, each block is represented by its ID, and the selection is represented
|
|
87
|
+
// by the `>|` and `|<` markers. So the selection starts in block `id-2` and
|
|
88
|
+
// ends in block `id-8`. In this case, the shared depth is 0, since the blocks
|
|
89
|
+
// `id-6`, `id-7`, and `id-8` set the shared depth, as they are the least
|
|
90
|
+
// nested blocks spanned by the selection. Therefore, these blocks are all
|
|
91
|
+
// added to the `blocks` array. However, the selection starts in block `id-2`,
|
|
92
|
+
// which is at a higher depth than the shared depth. So we add block `id-2` to
|
|
93
|
+
// the `blocks` array, as well as any later siblings (in this case, `id-3`),
|
|
94
|
+
// and move up one level of depth. The ancestor of block `id-2` at this depth
|
|
95
|
+
// is block `id-1`, so we add all its later siblings to the `blocks` array as
|
|
96
|
+
// well, again moving up one level of depth. Since we're now at the shared
|
|
97
|
+
// depth, we are done. The final `blocks` array for this example would be:
|
|
98
|
+
// [ id-2, id-3, id-4, id-6, id-7, id-8, id-9 ]
|
|
99
|
+
if ($startBlockBeforePos.depth > sharedDepth) {
|
|
100
|
+
// Adds the block that the selection starts in.
|
|
101
|
+
blocks.push(
|
|
102
|
+
nodeToBlock(
|
|
103
|
+
$startBlockBeforePos.nodeAfter!,
|
|
104
|
+
editor.schema.blockSchema,
|
|
105
|
+
editor.schema.inlineContentSchema,
|
|
106
|
+
editor.schema.styleSchema,
|
|
107
|
+
editor.blockCache
|
|
108
|
+
)
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// Traverses all depths from the depth of the block in which the selection
|
|
112
|
+
// starts, up to the shared depth.
|
|
113
|
+
for (let depth = $startBlockBeforePos.depth; depth > sharedDepth; depth--) {
|
|
114
|
+
const parentNode = $startBlockBeforePos.node(depth);
|
|
115
|
+
|
|
116
|
+
if (parentNode.type.isInGroup("childContainer")) {
|
|
117
|
+
const startIndexAtDepth = $startBlockBeforePos.index(depth) + 1;
|
|
118
|
+
const childCountAtDepth = $startBlockBeforePos.node(depth).childCount;
|
|
119
|
+
|
|
120
|
+
// Adds all blocks after the index of the block in which the selection
|
|
121
|
+
// starts (or its ancestors at lower depths).
|
|
122
|
+
for (let i = startIndexAtDepth; i < childCountAtDepth; i++) {
|
|
123
|
+
blocks.push(indexToBlock(i, depth));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
// Adds the first block spanned by the selection at the shared depth.
|
|
129
|
+
blocks.push(indexToBlock(startIndex, sharedDepth));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Adds all blocks spanned by the selection at the shared depth, excluding
|
|
133
|
+
// the first.
|
|
134
|
+
for (let i = startIndex + 1; i <= endIndex; i++) {
|
|
135
|
+
blocks.push(indexToBlock(i, sharedDepth));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (blocks.length === 0) {
|
|
139
|
+
throw new Error(
|
|
140
|
+
`Error getting selection - selection doesn't span any blocks (${state.selection})`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
blocks,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function setSelection<
|
|
150
|
+
BSchema extends BlockSchema,
|
|
151
|
+
I extends InlineContentSchema,
|
|
152
|
+
S extends StyleSchema
|
|
153
|
+
>(
|
|
154
|
+
editor: BlockNoteEditor<BSchema, I, S>,
|
|
155
|
+
startBlock: BlockIdentifier,
|
|
156
|
+
endBlock: BlockIdentifier
|
|
157
|
+
) {
|
|
158
|
+
const startBlockId =
|
|
159
|
+
typeof startBlock === "string" ? startBlock : startBlock.id;
|
|
160
|
+
const endBlockId = typeof endBlock === "string" ? endBlock : endBlock.id;
|
|
161
|
+
|
|
162
|
+
if (startBlockId === endBlockId) {
|
|
163
|
+
throw new Error(
|
|
164
|
+
`Attempting to set selection with the same anchor and head blocks (id ${startBlockId})`
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const doc = editor._tiptapEditor.state.doc;
|
|
169
|
+
|
|
170
|
+
const anchorPosInfo = getNodeById(startBlockId, doc);
|
|
171
|
+
if (!anchorPosInfo) {
|
|
172
|
+
throw new Error(`Block with ID ${startBlockId} not found`);
|
|
173
|
+
}
|
|
174
|
+
const headPosInfo = getNodeById(endBlockId, doc);
|
|
175
|
+
if (!headPosInfo) {
|
|
176
|
+
throw new Error(`Block with ID ${endBlockId} not found`);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const anchorBlockInfo = getBlockInfo(anchorPosInfo);
|
|
180
|
+
const headBlockInfo = getBlockInfo(headPosInfo);
|
|
181
|
+
|
|
182
|
+
const anchorBlockConfig =
|
|
183
|
+
editor.schema.blockSchema[
|
|
184
|
+
anchorBlockInfo.blockNoteType as keyof typeof editor.schema.blockSchema
|
|
185
|
+
];
|
|
186
|
+
const headBlockConfig =
|
|
187
|
+
editor.schema.blockSchema[
|
|
188
|
+
headBlockInfo.blockNoteType as keyof typeof editor.schema.blockSchema
|
|
189
|
+
];
|
|
190
|
+
|
|
191
|
+
if (
|
|
192
|
+
!anchorBlockInfo.isBlockContainer ||
|
|
193
|
+
anchorBlockConfig.content === "none"
|
|
194
|
+
) {
|
|
195
|
+
throw new Error(
|
|
196
|
+
`Attempting to set selection anchor in block without content (id ${startBlockId})`
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
if (!headBlockInfo.isBlockContainer || headBlockConfig.content === "none") {
|
|
200
|
+
throw new Error(
|
|
201
|
+
`Attempting to set selection anchor in block without content (id ${endBlockId})`
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
let startPos: number;
|
|
206
|
+
let endPos: number;
|
|
207
|
+
|
|
208
|
+
if (anchorBlockConfig.content === "table") {
|
|
209
|
+
const tableMap = TableMap.get(anchorBlockInfo.blockContent.node);
|
|
210
|
+
const firstCellPos =
|
|
211
|
+
anchorBlockInfo.blockContent.beforePos +
|
|
212
|
+
tableMap.positionAt(0, 0, anchorBlockInfo.blockContent.node) +
|
|
213
|
+
1;
|
|
214
|
+
startPos = firstCellPos + 2;
|
|
215
|
+
} else {
|
|
216
|
+
startPos = anchorBlockInfo.blockContent.beforePos + 1;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (headBlockConfig.content === "table") {
|
|
220
|
+
const tableMap = TableMap.get(headBlockInfo.blockContent.node);
|
|
221
|
+
const lastCellPos =
|
|
222
|
+
headBlockInfo.blockContent.beforePos +
|
|
223
|
+
tableMap.positionAt(
|
|
224
|
+
tableMap.height - 1,
|
|
225
|
+
tableMap.width - 1,
|
|
226
|
+
headBlockInfo.blockContent.node
|
|
227
|
+
) +
|
|
228
|
+
1;
|
|
229
|
+
const lastCellNodeSize = doc.resolve(lastCellPos).nodeAfter!.nodeSize;
|
|
230
|
+
endPos = lastCellPos + lastCellNodeSize - 2;
|
|
231
|
+
} else {
|
|
232
|
+
endPos = headBlockInfo.blockContent.afterPos - 1;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// TODO: We should polish up the `MultipleNodeSelection` and use that instead.
|
|
236
|
+
// Right now it's missing a few things like a jsonID and styling to show
|
|
237
|
+
// which nodes are selected. `TextSelection` is ok for now, but has the
|
|
238
|
+
// restriction that the start/end blocks must have content.
|
|
239
|
+
editor._tiptapEditor.dispatch(
|
|
240
|
+
editor._tiptapEditor.state.tr.setSelection(
|
|
241
|
+
TextSelection.create(editor._tiptapEditor.state.doc, startPos, endPos)
|
|
242
|
+
)
|
|
243
|
+
);
|
|
244
|
+
}
|
|
@@ -96,6 +96,10 @@ export function setTextCursorPosition<
|
|
|
96
96
|
const id = typeof targetBlock === "string" ? targetBlock : targetBlock.id;
|
|
97
97
|
|
|
98
98
|
const posInfo = getNodeById(id, editor._tiptapEditor.state.doc);
|
|
99
|
+
if (!posInfo) {
|
|
100
|
+
throw new Error(`Block with ID ${id} not found`);
|
|
101
|
+
}
|
|
102
|
+
|
|
99
103
|
const info = getBlockInfo(posInfo);
|
|
100
104
|
|
|
101
105
|
const contentType: "none" | "inline" | "table" =
|
|
@@ -18,9 +18,6 @@ export async function handleVSCodePaste<
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
const text = event.clipboardData!.getData("text/plain");
|
|
21
|
-
const vscode = event.clipboardData!.getData("vscode-editor-data");
|
|
22
|
-
const vscodeData = vscode ? JSON.parse(vscode) : undefined;
|
|
23
|
-
const language = vscodeData?.mode;
|
|
24
21
|
|
|
25
22
|
if (!text) {
|
|
26
23
|
return false;
|
|
@@ -28,10 +25,13 @@ export async function handleVSCodePaste<
|
|
|
28
25
|
|
|
29
26
|
if (!schema.nodes.codeBlock) {
|
|
30
27
|
view.pasteText(text);
|
|
31
|
-
|
|
32
28
|
return true;
|
|
33
29
|
}
|
|
34
30
|
|
|
31
|
+
const vscode = event.clipboardData!.getData("vscode-editor-data");
|
|
32
|
+
const vscodeData = vscode ? JSON.parse(vscode) : undefined;
|
|
33
|
+
const language = vscodeData?.mode;
|
|
34
|
+
|
|
35
35
|
if (!language) {
|
|
36
36
|
return false;
|
|
37
37
|
}
|
package/src/api/nodeUtil.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { Node } from "prosemirror-model";
|
|
|
6
6
|
export function getNodeById(
|
|
7
7
|
id: string,
|
|
8
8
|
doc: Node
|
|
9
|
-
): { node: Node; posBeforeNode: number } {
|
|
9
|
+
): { node: Node; posBeforeNode: number } | undefined {
|
|
10
10
|
let targetNode: Node | undefined = undefined;
|
|
11
11
|
let posBeforeNode: number | undefined = undefined;
|
|
12
12
|
|
|
@@ -28,7 +28,7 @@ export function getNodeById(
|
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
if (targetNode === undefined || posBeforeNode === undefined) {
|
|
31
|
-
|
|
31
|
+
return undefined;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
return {
|
|
@@ -47,11 +47,15 @@ const CodeBlockContent = createStronglyTypedTiptapNode({
|
|
|
47
47
|
};
|
|
48
48
|
},
|
|
49
49
|
addAttributes() {
|
|
50
|
+
const supportedLanguages = this.options
|
|
51
|
+
.supportedLanguages as SupportedLanguageConfig[];
|
|
52
|
+
|
|
50
53
|
return {
|
|
51
54
|
language: {
|
|
52
55
|
default: this.options.defaultLanguage,
|
|
53
56
|
parseHTML: (inputElement) => {
|
|
54
57
|
let element = inputElement as HTMLElement | null;
|
|
58
|
+
let language: string | null = null;
|
|
55
59
|
|
|
56
60
|
if (
|
|
57
61
|
element?.tagName === "DIV" &&
|
|
@@ -67,20 +71,26 @@ const CodeBlockContent = createStronglyTypedTiptapNode({
|
|
|
67
71
|
const dataLanguage = element?.getAttribute("data-language");
|
|
68
72
|
|
|
69
73
|
if (dataLanguage) {
|
|
70
|
-
|
|
74
|
+
language = dataLanguage.toLowerCase();
|
|
75
|
+
} else {
|
|
76
|
+
const classNames = [...(element?.className.split(" ") || [])];
|
|
77
|
+
const languages = classNames
|
|
78
|
+
.filter((className) => className.startsWith("language-"))
|
|
79
|
+
.map((className) => className.replace("language-", ""));
|
|
80
|
+
const [classLanguage] = languages;
|
|
81
|
+
|
|
82
|
+
language = classLanguage.toLowerCase();
|
|
71
83
|
}
|
|
72
84
|
|
|
73
|
-
const classNames = [...(element?.className.split(" ") || [])];
|
|
74
|
-
const languages = classNames
|
|
75
|
-
.filter((className) => className.startsWith("language-"))
|
|
76
|
-
.map((className) => className.replace("language-", ""));
|
|
77
|
-
const [language] = languages;
|
|
78
|
-
|
|
79
85
|
if (!language) {
|
|
80
86
|
return null;
|
|
81
87
|
}
|
|
82
88
|
|
|
83
|
-
return
|
|
89
|
+
return (
|
|
90
|
+
supportedLanguages.find(({ match }) => {
|
|
91
|
+
return match.includes(language);
|
|
92
|
+
})?.id || this.options.defaultLanguage
|
|
93
|
+
);
|
|
84
94
|
},
|
|
85
95
|
renderHTML: (attributes) => {
|
|
86
96
|
return attributes.language && attributes.language !== "text"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { bundledLanguagesInfo } from "shiki
|
|
1
|
+
import { bundledLanguagesInfo } from "shiki";
|
|
2
2
|
|
|
3
3
|
export type SupportedLanguageConfig = {
|
|
4
4
|
id: string;
|
|
@@ -14,23 +14,42 @@ export const defaultSupportedLanguages: SupportedLanguageConfig[] = [
|
|
|
14
14
|
},
|
|
15
15
|
...bundledLanguagesInfo
|
|
16
16
|
.filter((lang) => {
|
|
17
|
-
return
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"html
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
17
|
+
return [
|
|
18
|
+
"c",
|
|
19
|
+
"cpp",
|
|
20
|
+
"css",
|
|
21
|
+
"glsl",
|
|
22
|
+
"graphql",
|
|
23
|
+
"haml",
|
|
24
|
+
"html",
|
|
25
|
+
"java",
|
|
26
|
+
"javascript",
|
|
27
|
+
"json",
|
|
28
|
+
"jsonc",
|
|
29
|
+
"jsonl",
|
|
30
|
+
"jsx",
|
|
31
|
+
"julia",
|
|
32
|
+
"less",
|
|
33
|
+
"markdown",
|
|
34
|
+
"mdx",
|
|
35
|
+
"php",
|
|
36
|
+
"postcss",
|
|
37
|
+
"pug",
|
|
38
|
+
"python",
|
|
39
|
+
"r",
|
|
40
|
+
"regexp",
|
|
41
|
+
"sass",
|
|
42
|
+
"scss",
|
|
43
|
+
"shellscript",
|
|
44
|
+
"sql",
|
|
45
|
+
"svelte",
|
|
46
|
+
"typescript",
|
|
47
|
+
"vue",
|
|
48
|
+
"vue-html",
|
|
49
|
+
"wasm",
|
|
50
|
+
"wgsl",
|
|
51
|
+
"xml",
|
|
52
|
+
"yaml",
|
|
34
53
|
].includes(lang.id);
|
|
35
54
|
})
|
|
36
55
|
.map((lang) => ({
|
|
@@ -38,6 +57,7 @@ export const defaultSupportedLanguages: SupportedLanguageConfig[] = [
|
|
|
38
57
|
id: lang.id,
|
|
39
58
|
name: lang.name,
|
|
40
59
|
})),
|
|
60
|
+
{ id: "tsx", name: "TSX", match: ["tsx", "typescriptreact"] },
|
|
41
61
|
{
|
|
42
62
|
id: "haskell",
|
|
43
63
|
name: "Haskell",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { callOrReturn, Extension, getExtensionField } from "@tiptap/core";
|
|
2
|
-
import { columnResizing, tableEditing } from "prosemirror-tables";
|
|
2
|
+
import { columnResizing, goToNextCell, tableEditing } from "prosemirror-tables";
|
|
3
3
|
|
|
4
4
|
export const RESIZE_MIN_WIDTH = 35;
|
|
5
5
|
export const EMPTY_CELL_WIDTH = 120;
|
|
@@ -53,6 +53,17 @@ export const TableExtension = Extension.create({
|
|
|
53
53
|
selectionIsInTableParagraphNode
|
|
54
54
|
);
|
|
55
55
|
},
|
|
56
|
+
// Enables navigating cells using the tab key.
|
|
57
|
+
Tab: () => {
|
|
58
|
+
return this.editor.commands.command(({ state, dispatch, view }) =>
|
|
59
|
+
goToNextCell(1)(state, dispatch, view)
|
|
60
|
+
);
|
|
61
|
+
},
|
|
62
|
+
"Shift-Tab": () => {
|
|
63
|
+
return this.editor.commands.command(({ state, dispatch, view }) =>
|
|
64
|
+
goToNextCell(-1)(state, dispatch, view)
|
|
65
|
+
);
|
|
66
|
+
},
|
|
56
67
|
};
|
|
57
68
|
},
|
|
58
69
|
|
package/src/editor/Block.css
CHANGED
|
@@ -299,6 +299,9 @@ NESTED BLOCKS
|
|
|
299
299
|
transition: opacity 0.3s;
|
|
300
300
|
transition-delay: 1s;
|
|
301
301
|
}
|
|
302
|
+
.bn-block-content[data-content-type="codeBlock"] > div > select > option {
|
|
303
|
+
color: black;
|
|
304
|
+
}
|
|
302
305
|
.bn-block-content[data-content-type="codeBlock"]:hover > div > select,
|
|
303
306
|
.bn-block-content[data-content-type="codeBlock"] > div > select:focus {
|
|
304
307
|
opacity: 0.5;
|