@blocknote/core 0.3.0 → 0.4.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 +12698 -1341
- package/dist/blocknote.js.map +1 -1
- package/dist/blocknote.umd.cjs +50 -1
- package/dist/blocknote.umd.cjs.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +16 -5
- package/src/BlockNoteEditor.test.ts +12 -0
- package/src/BlockNoteEditor.ts +39 -15
- package/src/BlockNoteExtensions.ts +36 -32
- package/src/api/Editor.ts +226 -0
- package/src/api/blockManipulation/__snapshots__/blockManipulation.test.ts.snap +616 -0
- package/src/api/blockManipulation/blockManipulation.test.ts +172 -0
- package/src/api/blockManipulation/blockManipulation.ts +125 -0
- package/src/api/formatConversions/__snapshots__/formatConversions.test.ts.snap +346 -0
- package/src/api/formatConversions/formatConversions.test.ts +766 -0
- package/src/api/formatConversions/formatConversions.ts +86 -0
- package/src/api/formatConversions/removeUnderlinesRehypePlugin.ts +39 -0
- package/src/api/formatConversions/simplifyBlocksRehypePlugin.ts +125 -0
- package/src/api/nodeConversions/__snapshots__/nodeConversions.test.ts.snap +268 -0
- package/src/api/nodeConversions/nodeConversions.test.ts +244 -0
- package/src/api/nodeConversions/nodeConversions.ts +279 -0
- package/src/api/nodeConversions/testUtil.ts +61 -0
- package/src/api/util/nodeUtil.ts +38 -0
- package/src/editor.module.css +8 -1
- package/src/extensions/Blocks/PreviousBlockTypePlugin.ts +7 -1
- package/src/extensions/Blocks/api/blockTypes.ts +90 -0
- package/src/extensions/Blocks/api/cursorPositionTypes.ts +5 -0
- package/src/extensions/Blocks/api/inlineContentTypes.ts +35 -0
- package/src/extensions/Blocks/helpers/getBlockInfoFromPos.ts +4 -4
- package/src/extensions/Blocks/nodes/Block.module.css +39 -36
- package/src/extensions/Blocks/nodes/BlockContainer.ts +74 -23
- package/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts +23 -5
- package/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts +28 -6
- package/src/extensions/DraggableBlocks/DraggableBlocksPlugin.ts +149 -87
- package/src/extensions/FormattingToolbar/FormattingToolbarFactoryTypes.ts +2 -2
- package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +3 -3
- package/src/extensions/SlashMenu/SlashMenuExtension.ts +7 -12
- package/src/extensions/SlashMenu/SlashMenuItem.ts +4 -1
- package/src/extensions/SlashMenu/{defaultCommands.tsx → defaultSlashCommands.tsx} +34 -17
- package/src/extensions/SlashMenu/index.ts +7 -4
- package/src/extensions/UniqueID/UniqueID.ts +1 -1
- package/src/index.ts +4 -2
- package/src/shared/utils.ts +6 -0
- package/types/src/BlockNoteEditor.d.ts +13 -4
- package/types/src/BlockNoteEditor.test.d.ts +1 -0
- package/types/src/BlockNoteExtensions.d.ts +7 -3
- package/types/src/api/Editor.d.ts +93 -0
- package/types/src/api/blockManipulation/blockManipulation.d.ts +6 -0
- package/types/src/api/blockManipulation/blockManipulation.test.d.ts +1 -0
- package/types/src/api/formatConversions/formatConversions.d.ts +6 -0
- package/types/src/api/formatConversions/formatConversions.test.d.ts +1 -0
- package/types/src/api/formatConversions/removeUnderlinesRehypePlugin.d.ts +6 -0
- package/types/src/api/formatConversions/simplifyBlocksRehypePlugin.d.ts +16 -0
- package/types/src/api/nodeConversions/nodeConversions.d.ts +15 -0
- package/types/src/api/nodeConversions/nodeConversions.test.d.ts +1 -0
- package/types/src/api/nodeConversions/testUtil.d.ts +2 -0
- package/types/src/api/util/nodeUtil.d.ts +8 -0
- package/types/src/extensions/Blocks/api/blockTypes.d.ts +37 -0
- package/types/src/extensions/Blocks/api/cursorPositionTypes.d.ts +4 -0
- package/types/src/extensions/Blocks/api/inlineContentTypes.d.ts +29 -0
- package/types/src/extensions/Blocks/nodes/BlockContainer.d.ts +3 -3
- package/types/src/extensions/DraggableBlocks/DraggableBlocksPlugin.d.ts +15 -0
- package/types/src/extensions/FormattingToolbar/FormattingToolbarFactoryTypes.d.ts +2 -2
- package/types/src/extensions/SlashMenu/SlashMenuExtension.d.ts +1 -3
- package/types/src/extensions/SlashMenu/SlashMenuItem.d.ts +4 -1
- package/types/src/extensions/SlashMenu/index.d.ts +3 -3
- package/types/src/index.d.ts +4 -2
- package/types/src/shared/utils.d.ts +3 -0
- package/src/extensions/Blocks/apiTypes.ts +0 -48
- package/types/src/EditorElement.d.ts +0 -7
- package/types/src/api/Document.d.ts +0 -5
- package/types/src/extensions/Blocks/BlockAttributes.d.ts +0 -2
- package/types/src/extensions/Blocks/MultipleNodeSelection.d.ts +0 -24
- package/types/src/extensions/Blocks/apiTypes.d.ts +0 -16
- package/types/src/extensions/Blocks/nodes/Block.d.ts +0 -24
- package/types/src/extensions/Blocks/nodes/BlockContent/BlockContentTypes.d.ts +0 -4
- package/types/src/extensions/Blocks/nodes/BlockContent/HeadingBlockContent/HeadingBlockContentTypes.d.ts +0 -4
- package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContentTypes.d.ts +0 -2
- package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContentTypes.d.ts +0 -2
- package/types/src/extensions/Blocks/nodes/BlockContent/ParagraphBlockContent/ParagraphBlockContentTypes.d.ts +0 -2
- package/types/src/extensions/Blocks/nodes/BlockTypes/HeadingBlock/HeadingContent.d.ts +0 -8
- package/types/src/extensions/Blocks/nodes/BlockTypes/ListItemBlock/ListItemContent.d.ts +0 -8
- package/types/src/extensions/Blocks/nodes/BlockTypes/ListItemBlock/OrderedListItemIndexPlugin.d.ts +0 -2
- package/types/src/extensions/Blocks/nodes/BlockTypes/TextBlock/TextContent.d.ts +0 -6
- package/types/src/extensions/BubbleMenu/BubbleMenuExtension.d.ts +0 -8
- package/types/src/extensions/BubbleMenu/BubbleMenuFactoryTypes.d.ts +0 -27
- package/types/src/extensions/BubbleMenu/BubbleMenuPlugin.d.ts +0 -44
- package/types/src/extensions/DraggableBlocks/BlockMenuFactoryTypes.d.ts +0 -12
- package/types/src/extensions/DraggableBlocks/DragMenuFactoryTypes.d.ts +0 -18
- package/types/src/extensions/Hyperlinks/HyperlinkMark.d.ts +0 -8
- package/types/src/extensions/Hyperlinks/HyperlinkMenuFactoryTypes.d.ts +0 -11
- package/types/src/extensions/Hyperlinks/HyperlinkMenuPlugin.d.ts +0 -11
- package/types/src/extensions/Paragraph/FixedParagraph.d.ts +0 -1
- package/types/src/extensions/SlashMenu/defaultCommands.d.ts +0 -8
- package/types/src/utils.d.ts +0 -2
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/** Define the main block types **/
|
|
2
|
+
|
|
3
|
+
import { InlineContent, PartialInlineContent } from "./inlineContentTypes";
|
|
4
|
+
|
|
5
|
+
export type BlockTemplate<
|
|
6
|
+
// Type of the block.
|
|
7
|
+
// Examples might include: "paragraph", "heading", or "bulletListItem".
|
|
8
|
+
Type extends string,
|
|
9
|
+
// Changeable props which affect the block's behaviour or appearance.
|
|
10
|
+
// An example might be: { textAlignment: "left" | "right" | "center" } for a paragraph block.
|
|
11
|
+
Props extends Record<string, string>
|
|
12
|
+
> = {
|
|
13
|
+
id: string;
|
|
14
|
+
type: Type;
|
|
15
|
+
props: Props;
|
|
16
|
+
content: InlineContent[];
|
|
17
|
+
children: Block[];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type DefaultBlockProps = {
|
|
21
|
+
backgroundColor: string;
|
|
22
|
+
textColor: string;
|
|
23
|
+
textAlignment: "left" | "center" | "right" | "justify";
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type NumberedListItemBlock = BlockTemplate<
|
|
27
|
+
"numberedListItem",
|
|
28
|
+
DefaultBlockProps
|
|
29
|
+
>;
|
|
30
|
+
|
|
31
|
+
export type BulletListItemBlock = BlockTemplate<
|
|
32
|
+
"bulletListItem",
|
|
33
|
+
DefaultBlockProps
|
|
34
|
+
>;
|
|
35
|
+
|
|
36
|
+
export type HeadingBlock = BlockTemplate<
|
|
37
|
+
"heading",
|
|
38
|
+
DefaultBlockProps & {
|
|
39
|
+
level: "1" | "2" | "3";
|
|
40
|
+
}
|
|
41
|
+
>;
|
|
42
|
+
|
|
43
|
+
export type ParagraphBlock = BlockTemplate<"paragraph", DefaultBlockProps>;
|
|
44
|
+
|
|
45
|
+
export type Block =
|
|
46
|
+
| ParagraphBlock
|
|
47
|
+
| HeadingBlock
|
|
48
|
+
| BulletListItemBlock
|
|
49
|
+
| NumberedListItemBlock;
|
|
50
|
+
|
|
51
|
+
export type BlockIdentifier = string | Block;
|
|
52
|
+
|
|
53
|
+
/** Define "Partial Blocks", these are for updating or creating blocks */
|
|
54
|
+
export type PartialBlockTemplate<B extends Block> = B extends Block
|
|
55
|
+
? Partial<Omit<B, "props" | "children" | "content" | "type">> & {
|
|
56
|
+
type?: B["type"];
|
|
57
|
+
props?: Partial<B["props"]>;
|
|
58
|
+
content?: string | PartialInlineContent[];
|
|
59
|
+
children?: PartialBlock[];
|
|
60
|
+
}
|
|
61
|
+
: never;
|
|
62
|
+
|
|
63
|
+
export type PartialBlock = PartialBlockTemplate<Block>;
|
|
64
|
+
|
|
65
|
+
export type BlockPropsTemplate<Props> = Props extends Block["props"]
|
|
66
|
+
? keyof Props
|
|
67
|
+
: never;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Expose blockProps. This is currently not very nice, but it's expected this
|
|
71
|
+
* will change anyway once we allow for custom blocks
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
export const globalProps: Array<keyof DefaultBlockProps> = [
|
|
75
|
+
"backgroundColor",
|
|
76
|
+
"textColor",
|
|
77
|
+
"textAlignment",
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
export const blockProps: Record<Block["type"], Set<string>> = {
|
|
81
|
+
paragraph: new Set<keyof ParagraphBlock["props"]>([...globalProps]),
|
|
82
|
+
heading: new Set<keyof HeadingBlock["props"]>([
|
|
83
|
+
...globalProps,
|
|
84
|
+
"level" as const,
|
|
85
|
+
]),
|
|
86
|
+
numberedListItem: new Set<keyof NumberedListItemBlock["props"]>([
|
|
87
|
+
...globalProps,
|
|
88
|
+
]),
|
|
89
|
+
bulletListItem: new Set<keyof BulletListItemBlock["props"]>([...globalProps]),
|
|
90
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type Styles = {
|
|
2
|
+
bold?: true;
|
|
3
|
+
italic?: true;
|
|
4
|
+
underline?: true;
|
|
5
|
+
strike?: true;
|
|
6
|
+
textColor?: string;
|
|
7
|
+
backgroundColor?: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type ToggledStyles = {
|
|
11
|
+
[K in keyof Styles]-?: Required<Styles>[K] extends true ? K : never;
|
|
12
|
+
}[keyof Styles];
|
|
13
|
+
|
|
14
|
+
export type ColorStyles = {
|
|
15
|
+
[K in keyof Styles]-?: Required<Styles>[K] extends string ? K : never;
|
|
16
|
+
}[keyof Styles];
|
|
17
|
+
|
|
18
|
+
export type StyledText = {
|
|
19
|
+
type: "text";
|
|
20
|
+
text: string;
|
|
21
|
+
styles: Styles;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type Link = {
|
|
25
|
+
type: "link";
|
|
26
|
+
href: string;
|
|
27
|
+
content: StyledText[];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type PartialLink = Omit<Link, "content"> & {
|
|
31
|
+
content: string | Link["content"];
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type InlineContent = StyledText | Link;
|
|
35
|
+
export type PartialInlineContent = StyledText | PartialLink;
|
|
@@ -22,7 +22,7 @@ export function getBlockInfoFromPos(
|
|
|
22
22
|
doc: Node,
|
|
23
23
|
posInBlock: number
|
|
24
24
|
): BlockInfo | undefined {
|
|
25
|
-
if (posInBlock
|
|
25
|
+
if (posInBlock < 0 || posInBlock > doc.nodeSize) {
|
|
26
26
|
return undefined;
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -32,11 +32,11 @@ export function getBlockInfoFromPos(
|
|
|
32
32
|
let node = $pos.node(maxDepth);
|
|
33
33
|
let depth = maxDepth;
|
|
34
34
|
|
|
35
|
-
while (
|
|
36
|
-
|
|
37
|
-
if (depth === 0) {
|
|
35
|
+
while (true) {
|
|
36
|
+
if (depth < 0) {
|
|
38
37
|
return undefined;
|
|
39
38
|
}
|
|
39
|
+
|
|
40
40
|
if (node.type.name === "blockContainer") {
|
|
41
41
|
break;
|
|
42
42
|
}
|
|
@@ -35,6 +35,7 @@ BASIC STYLES
|
|
|
35
35
|
.blockContent h2,
|
|
36
36
|
.blockContent h3,
|
|
37
37
|
.blockContent li {
|
|
38
|
+
all: unset;
|
|
38
39
|
margin: 0;
|
|
39
40
|
padding: 0;
|
|
40
41
|
font-size: inherit;
|
|
@@ -150,75 +151,79 @@ NESTED BLOCKS
|
|
|
150
151
|
|
|
151
152
|
/* Ordered */
|
|
152
153
|
[data-content-type="numberedListItem"] {
|
|
153
|
-
--index: attr(data-index)
|
|
154
|
+
--index: attr(data-index);
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
[data-prev-type="numberedListItem"] {
|
|
157
|
-
--prev-index: attr(data-prev-index)
|
|
158
|
+
--prev-index: attr(data-prev-index);
|
|
158
159
|
}
|
|
159
160
|
|
|
160
161
|
.blockOuter[data-prev-type="numberedListItem"]:not([data-prev-index="none"])
|
|
161
|
-
> .block
|
|
162
|
-
> .blockContent::before {
|
|
162
|
+
> .block
|
|
163
|
+
> .blockContent::before {
|
|
163
164
|
margin-right: 1.2em;
|
|
164
|
-
content: var(--prev-index)".";
|
|
165
|
+
content: var(--prev-index) ".";
|
|
165
166
|
}
|
|
166
167
|
|
|
167
168
|
.blockOuter:not([data-prev-type])
|
|
168
|
-
> .block
|
|
169
|
-
> .blockContent[data-content-type="numberedListItem"]::before {
|
|
169
|
+
> .block
|
|
170
|
+
> .blockContent[data-content-type="numberedListItem"]::before {
|
|
170
171
|
margin-right: 1.2em;
|
|
171
|
-
content: var(--index)".";
|
|
172
|
+
content: var(--index) ".";
|
|
172
173
|
}
|
|
173
174
|
|
|
174
175
|
/* Unordered */
|
|
175
176
|
/* No list nesting */
|
|
176
|
-
.blockOuter[data-prev-type="bulletListItem"]
|
|
177
|
-
> .block
|
|
178
|
-
> .blockContent::before {
|
|
177
|
+
.blockOuter[data-prev-type="bulletListItem"] > .block > .blockContent::before {
|
|
179
178
|
margin-right: 1.2em;
|
|
180
179
|
content: "•";
|
|
181
180
|
}
|
|
182
181
|
|
|
183
182
|
.blockOuter:not([data-prev-type])
|
|
184
|
-
> .block
|
|
185
|
-
> .blockContent[data-content-type="bulletListItem"]::before {
|
|
183
|
+
> .block
|
|
184
|
+
> .blockContent[data-content-type="bulletListItem"]::before {
|
|
186
185
|
margin-right: 1.2em;
|
|
187
186
|
content: "•";
|
|
188
187
|
}
|
|
189
188
|
|
|
190
189
|
/* 1 level of list nesting */
|
|
191
|
-
[data-content-type="bulletListItem"]
|
|
192
|
-
|
|
193
|
-
> .
|
|
194
|
-
> .
|
|
190
|
+
[data-content-type="bulletListItem"]
|
|
191
|
+
~ .blockGroup
|
|
192
|
+
> .blockOuter[data-prev-type="bulletListItem"]
|
|
193
|
+
> .block
|
|
194
|
+
> .blockContent::before {
|
|
195
195
|
margin-right: 1.2em;
|
|
196
196
|
content: "◦";
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
-
[data-content-type="bulletListItem"]
|
|
200
|
-
|
|
201
|
-
> .
|
|
202
|
-
> .
|
|
199
|
+
[data-content-type="bulletListItem"]
|
|
200
|
+
~ .blockGroup
|
|
201
|
+
> .blockOuter:not([data-prev-type])
|
|
202
|
+
> .block
|
|
203
|
+
> .blockContent[data-content-type="bulletListItem"]::before {
|
|
203
204
|
margin-right: 1.2em;
|
|
204
205
|
content: "◦";
|
|
205
206
|
}
|
|
206
207
|
|
|
207
208
|
/* 2 levels of list nesting */
|
|
208
|
-
[data-content-type="bulletListItem"]
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
> .
|
|
209
|
+
[data-content-type="bulletListItem"]
|
|
210
|
+
~ .blockGroup
|
|
211
|
+
[data-content-type="bulletListItem"]
|
|
212
|
+
~ .blockGroup
|
|
213
|
+
> .blockOuter[data-prev-type="bulletListItem"]
|
|
214
|
+
> .block
|
|
215
|
+
> .blockContent::before {
|
|
213
216
|
margin-right: 1.2em;
|
|
214
217
|
content: "▪";
|
|
215
218
|
}
|
|
216
219
|
|
|
217
|
-
[data-content-type="bulletListItem"]
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
> .
|
|
220
|
+
[data-content-type="bulletListItem"]
|
|
221
|
+
~ .blockGroup
|
|
222
|
+
[data-content-type="bulletListItem"]
|
|
223
|
+
~ .blockGroup
|
|
224
|
+
> .blockOuter:not([data-prev-type])
|
|
225
|
+
> .block
|
|
226
|
+
> .blockContent[data-content-type="bulletListItem"]::before {
|
|
222
227
|
margin-right: 1.2em;
|
|
223
228
|
content: "▪";
|
|
224
229
|
}
|
|
@@ -251,15 +256,13 @@ NESTED BLOCKS
|
|
|
251
256
|
content: "Type to filter";
|
|
252
257
|
}
|
|
253
258
|
|
|
254
|
-
.blockContent[data-content-type="heading"].isEmpty
|
|
255
|
-
> :first-child::before {
|
|
259
|
+
.blockContent[data-content-type="heading"].isEmpty > :first-child::before {
|
|
256
260
|
content: "Heading";
|
|
257
261
|
}
|
|
258
262
|
|
|
259
|
-
.blockContent[data-content-type="bulletListItem"].isEmpty
|
|
260
|
-
> :first-child:before,
|
|
263
|
+
.blockContent[data-content-type="bulletListItem"].isEmpty > :first-child:before,
|
|
261
264
|
.blockContent[data-content-type="numberedListItem"].isEmpty
|
|
262
|
-
> :first-child:before {
|
|
265
|
+
> :first-child:before {
|
|
263
266
|
content: "List";
|
|
264
267
|
}
|
|
265
268
|
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { mergeAttributes, Node } from "@tiptap/core";
|
|
2
|
-
import { Fragment, Slice } from "prosemirror-model";
|
|
2
|
+
import { Fragment, Node as PMNode, Slice } from "prosemirror-model";
|
|
3
3
|
import { TextSelection } from "prosemirror-state";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
blockToNode,
|
|
6
|
+
inlineContentToNodes,
|
|
7
|
+
} from "../../../api/nodeConversions/nodeConversions";
|
|
8
|
+
import { PartialBlock } from "../api/blockTypes";
|
|
5
9
|
import { getBlockInfoFromPos } from "../helpers/getBlockInfoFromPos";
|
|
6
10
|
import { PreviousBlockTypePlugin } from "../PreviousBlockTypePlugin";
|
|
7
11
|
import styles from "./Block.module.css";
|
|
@@ -19,13 +23,10 @@ declare module "@tiptap/core" {
|
|
|
19
23
|
BNDeleteBlock: (posInBlock: number) => ReturnType;
|
|
20
24
|
BNMergeBlocks: (posBetweenBlocks: number) => ReturnType;
|
|
21
25
|
BNSplitBlock: (posInBlock: number, keepType: boolean) => ReturnType;
|
|
22
|
-
BNUpdateBlock: (
|
|
23
|
-
posInBlock: number,
|
|
24
|
-
blockUpdate: BlockUpdate
|
|
25
|
-
) => ReturnType;
|
|
26
|
+
BNUpdateBlock: (posInBlock: number, block: PartialBlock) => ReturnType;
|
|
26
27
|
BNCreateOrUpdateBlock: (
|
|
27
28
|
posInBlock: number,
|
|
28
|
-
|
|
29
|
+
block: PartialBlock
|
|
29
30
|
) => ReturnType;
|
|
30
31
|
};
|
|
31
32
|
}
|
|
@@ -197,8 +198,7 @@ export const BlockContainer = Node.create<IBlock>({
|
|
|
197
198
|
}
|
|
198
199
|
|
|
199
200
|
// Deletes next block and adds its text content to the nearest previous block.
|
|
200
|
-
// TODO:
|
|
201
|
-
// is trickier.
|
|
201
|
+
// TODO: Use slices.
|
|
202
202
|
if (dispatch) {
|
|
203
203
|
state.tr.deleteRange(startPos, startPos + contentNode.nodeSize);
|
|
204
204
|
state.tr.insertText(contentNode.textContent, prevBlockEndPos - 1);
|
|
@@ -283,35 +283,86 @@ export const BlockContainer = Node.create<IBlock>({
|
|
|
283
283
|
|
|
284
284
|
return true;
|
|
285
285
|
},
|
|
286
|
-
// Updates
|
|
286
|
+
// Updates a block to the given specification.
|
|
287
287
|
BNUpdateBlock:
|
|
288
|
-
(posInBlock,
|
|
288
|
+
(posInBlock, block) =>
|
|
289
289
|
({ state, dispatch }) => {
|
|
290
290
|
const blockInfo = getBlockInfoFromPos(state.doc, posInBlock);
|
|
291
291
|
if (blockInfo === undefined) {
|
|
292
292
|
return false;
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
-
const {
|
|
295
|
+
const { startPos, endPos, node, contentNode } = blockInfo;
|
|
296
296
|
|
|
297
297
|
if (dispatch) {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
298
|
+
// Adds blockGroup node with child blocks if necessary.
|
|
299
|
+
if (block.children !== undefined) {
|
|
300
|
+
const childNodes = [];
|
|
301
|
+
|
|
302
|
+
// Creates ProseMirror nodes for each child block, including their descendants.
|
|
303
|
+
for (const child of block.children) {
|
|
304
|
+
childNodes.push(blockToNode(child, state.schema));
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Checks if a blockGroup node already exists.
|
|
308
|
+
if (node.childCount === 2) {
|
|
309
|
+
// Replaces all child nodes in the existing blockGroup with the ones created earlier.
|
|
310
|
+
state.tr.replace(
|
|
311
|
+
startPos + contentNode.nodeSize + 1,
|
|
312
|
+
endPos - 1,
|
|
313
|
+
new Slice(Fragment.from(childNodes), 0, 0)
|
|
314
|
+
);
|
|
315
|
+
} else {
|
|
316
|
+
// Inserts a new blockGroup containing the child nodes created earlier.
|
|
317
|
+
state.tr.insert(
|
|
318
|
+
startPos + contentNode.nodeSize,
|
|
319
|
+
state.schema.nodes["blockGroup"].create({}, childNodes)
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Replaces the blockContent node's content if necessary.
|
|
325
|
+
if (block.content !== undefined) {
|
|
326
|
+
let content: PMNode[] = [];
|
|
327
|
+
|
|
328
|
+
// Checks if the provided content is a string or InlineContent[] type.
|
|
329
|
+
if (typeof block.content === "string") {
|
|
330
|
+
// Adds a single text node with no marks to the content.
|
|
331
|
+
content.push(state.schema.text(block.content));
|
|
332
|
+
} else {
|
|
333
|
+
// Adds a text node with the provided styles converted into marks to the content, for each InlineContent
|
|
334
|
+
// object.
|
|
335
|
+
content = inlineContentToNodes(block.content, state.schema);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Replaces the contents of the blockContent node with the previously created text node(s).
|
|
339
|
+
state.tr.replace(
|
|
340
|
+
startPos + 1,
|
|
341
|
+
startPos + contentNode.nodeSize - 1,
|
|
342
|
+
new Slice(Fragment.from(content), 0, 0)
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Changes the block type and adds the provided props as node attributes. Also preserves all existing node
|
|
347
|
+
// attributes that are compatible with the new type.
|
|
348
|
+
state.tr.setNodeMarkup(
|
|
349
|
+
startPos,
|
|
350
|
+
block.type === undefined
|
|
351
|
+
? undefined
|
|
352
|
+
: state.schema.nodes[block.type],
|
|
302
353
|
{
|
|
303
|
-
...
|
|
304
|
-
...
|
|
354
|
+
...contentNode.attrs,
|
|
355
|
+
...block.props,
|
|
305
356
|
}
|
|
306
357
|
);
|
|
307
358
|
}
|
|
308
359
|
|
|
309
360
|
return true;
|
|
310
361
|
},
|
|
311
|
-
//
|
|
312
|
-
//
|
|
362
|
+
// Updates a block to the given specification if it's empty, otherwise creates a new block from that specification
|
|
363
|
+
// below it.
|
|
313
364
|
BNCreateOrUpdateBlock:
|
|
314
|
-
(posInBlock,
|
|
365
|
+
(posInBlock, block) =>
|
|
315
366
|
({ state, chain }) => {
|
|
316
367
|
const blockInfo = getBlockInfoFromPos(state.doc, posInBlock);
|
|
317
368
|
if (blockInfo === undefined) {
|
|
@@ -324,7 +375,7 @@ export const BlockContainer = Node.create<IBlock>({
|
|
|
324
375
|
const oldBlockContentPos = startPos + 1;
|
|
325
376
|
|
|
326
377
|
return chain()
|
|
327
|
-
.BNUpdateBlock(posInBlock,
|
|
378
|
+
.BNUpdateBlock(posInBlock, block)
|
|
328
379
|
.setTextSelection(oldBlockContentPos)
|
|
329
380
|
.run();
|
|
330
381
|
} else {
|
|
@@ -333,7 +384,7 @@ export const BlockContainer = Node.create<IBlock>({
|
|
|
333
384
|
|
|
334
385
|
return chain()
|
|
335
386
|
.BNCreateBlock(newBlockInsertionPos)
|
|
336
|
-
.BNUpdateBlock(newBlockContentPos,
|
|
387
|
+
.BNUpdateBlock(newBlockContentPos, block)
|
|
337
388
|
.setTextSelection(newBlockContentPos)
|
|
338
389
|
.run();
|
|
339
390
|
}
|
|
@@ -33,6 +33,7 @@ export const BulletListItemBlockContent = Node.create({
|
|
|
33
33
|
|
|
34
34
|
parseHTML() {
|
|
35
35
|
return [
|
|
36
|
+
// Case for regular HTML list structure.
|
|
36
37
|
{
|
|
37
38
|
tag: "li",
|
|
38
39
|
getAttrs: (element) => {
|
|
@@ -46,18 +47,35 @@ export const BulletListItemBlockContent = Node.create({
|
|
|
46
47
|
return false;
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
if (parent.getAttribute("data-content-type") === "bulletListItem") {
|
|
50
|
+
if (parent.tagName === "UL") {
|
|
51
51
|
return {};
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
return false;
|
|
55
|
+
},
|
|
56
|
+
node: "blockContainer",
|
|
57
|
+
},
|
|
58
|
+
// Case for BlockNote list structure.
|
|
59
|
+
{
|
|
60
|
+
tag: "p",
|
|
61
|
+
getAttrs: (element) => {
|
|
62
|
+
if (typeof element === "string") {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const parent = element.parentElement;
|
|
67
|
+
|
|
68
|
+
if (parent === null) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (parent.getAttribute("data-content-type") === "bulletListItem") {
|
|
56
73
|
return {};
|
|
57
74
|
}
|
|
58
75
|
|
|
59
76
|
return false;
|
|
60
77
|
},
|
|
78
|
+
priority: 300,
|
|
61
79
|
node: "blockContainer",
|
|
62
80
|
},
|
|
63
81
|
];
|
|
@@ -70,7 +88,7 @@ export const BulletListItemBlockContent = Node.create({
|
|
|
70
88
|
class: styles.blockContent,
|
|
71
89
|
"data-content-type": this.name,
|
|
72
90
|
}),
|
|
73
|
-
["
|
|
91
|
+
["p", 0],
|
|
74
92
|
];
|
|
75
93
|
},
|
|
76
94
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { InputRule, mergeAttributes, Node } from "@tiptap/core";
|
|
2
|
-
import { NumberedListIndexingPlugin } from "./NumberedListIndexingPlugin";
|
|
3
2
|
import styles from "../../../Block.module.css";
|
|
4
3
|
import { handleEnter } from "../ListItemKeyboardShortcuts";
|
|
4
|
+
import { NumberedListIndexingPlugin } from "./NumberedListIndexingPlugin";
|
|
5
5
|
|
|
6
6
|
export const NumberedListItemBlockContent = Node.create({
|
|
7
7
|
name: "numberedListItem",
|
|
@@ -52,6 +52,8 @@ export const NumberedListItemBlockContent = Node.create({
|
|
|
52
52
|
|
|
53
53
|
parseHTML() {
|
|
54
54
|
return [
|
|
55
|
+
// Case for regular HTML list structure.
|
|
56
|
+
// (e.g.: when pasting from other apps)
|
|
55
57
|
{
|
|
56
58
|
tag: "li",
|
|
57
59
|
getAttrs: (element) => {
|
|
@@ -65,18 +67,36 @@ export const NumberedListItemBlockContent = Node.create({
|
|
|
65
67
|
return false;
|
|
66
68
|
}
|
|
67
69
|
|
|
68
|
-
|
|
69
|
-
if (parent.getAttribute("data-content-type") === "numberedListItem") {
|
|
70
|
+
if (parent.tagName === "OL") {
|
|
70
71
|
return {};
|
|
71
72
|
}
|
|
72
73
|
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
return false;
|
|
75
|
+
},
|
|
76
|
+
node: "blockContainer",
|
|
77
|
+
},
|
|
78
|
+
// Case for BlockNote list structure.
|
|
79
|
+
// (e.g.: when pasting from blocknote)
|
|
80
|
+
{
|
|
81
|
+
tag: "p",
|
|
82
|
+
getAttrs: (element) => {
|
|
83
|
+
if (typeof element === "string") {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const parent = element.parentElement;
|
|
88
|
+
|
|
89
|
+
if (parent === null) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (parent.getAttribute("data-content-type") === "numberedListItem") {
|
|
75
94
|
return {};
|
|
76
95
|
}
|
|
77
96
|
|
|
78
97
|
return false;
|
|
79
98
|
},
|
|
99
|
+
priority: 300,
|
|
80
100
|
node: "blockContainer",
|
|
81
101
|
},
|
|
82
102
|
];
|
|
@@ -89,7 +109,9 @@ export const NumberedListItemBlockContent = Node.create({
|
|
|
89
109
|
class: styles.blockContent,
|
|
90
110
|
"data-content-type": this.name,
|
|
91
111
|
}),
|
|
92
|
-
|
|
112
|
+
// we use a <p> tag, because for <li> tags we'd need to add a <ul> parent for around siblings to be semantically correct,
|
|
113
|
+
// which would be quite cumbersome
|
|
114
|
+
["p", 0],
|
|
93
115
|
];
|
|
94
116
|
},
|
|
95
117
|
});
|