@blocknote/core 0.13.3 → 0.13.4
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 +1038 -696
- package/dist/blocknote.js.map +1 -1
- package/dist/blocknote.umd.cjs +6 -6
- package/dist/blocknote.umd.cjs.map +1 -1
- package/dist/style.css +1 -1
- package/dist/webpack-stats.json +1 -1
- package/package.json +2 -2
- package/src/api/exporters/html/__snapshots__/image/basic/internal.html +1 -1
- package/src/api/exporters/html/__snapshots__/image/nested/internal.html +1 -1
- package/src/api/exporters/html/__snapshots__/image/noCaption/internal.html +1 -1
- package/src/api/exporters/html/__snapshots__/image/noName/internal.html +1 -1
- package/src/api/exporters/html/__snapshots__/lists/basic/external.html +1 -0
- package/src/api/exporters/html/__snapshots__/lists/basic/internal.html +1 -0
- package/src/api/exporters/html/__snapshots__/lists/nested/external.html +1 -0
- package/src/api/exporters/html/__snapshots__/lists/nested/internal.html +1 -0
- package/src/api/exporters/html/__snapshots__/simpleImage/basic/external.html +1 -1
- package/src/api/exporters/html/__snapshots__/simpleImage/basic/internal.html +1 -1
- package/src/api/exporters/html/__snapshots__/simpleImage/nested/external.html +1 -1
- package/src/api/exporters/html/__snapshots__/simpleImage/nested/internal.html +1 -1
- package/src/api/exporters/html/__snapshots__/simpleImage/noCaption/external.html +1 -1
- package/src/api/exporters/html/__snapshots__/simpleImage/noCaption/internal.html +1 -1
- package/src/api/exporters/html/__snapshots__/simpleImage/noName/external.html +1 -1
- package/src/api/exporters/html/__snapshots__/simpleImage/noName/internal.html +1 -1
- package/src/api/exporters/html/externalHTMLExporter.ts +4 -3
- package/src/api/exporters/html/util/simplifyBlocksRehypePlugin.ts +1 -1
- package/src/api/exporters/markdown/__snapshots__/lists/basic/markdown.md +8 -0
- package/src/api/exporters/markdown/__snapshots__/lists/nested/markdown.md +10 -0
- package/src/api/exporters/markdown/__snapshots__/simpleImage/basic/markdown.md +1 -1
- package/src/api/exporters/markdown/__snapshots__/simpleImage/nested/markdown.md +2 -2
- package/src/api/exporters/markdown/__snapshots__/simpleImage/noCaption/markdown.md +1 -1
- package/src/api/exporters/markdown/__snapshots__/simpleImage/noName/markdown.md +1 -1
- package/src/api/exporters/markdown/markdownExporter.ts +2 -0
- package/src/api/exporters/markdown/util/addSpacesToCheckboxesRehypePlugin.ts +42 -0
- package/src/api/nodeConversions/__snapshots__/nodeConversions.test.ts.snap +50 -0
- package/src/api/parsers/html/__snapshots__/paste/list-test.json +74 -2
- package/src/api/parsers/html/__snapshots__/paste/parse-mixed-nested-lists.json +135 -10
- package/src/api/parsers/html/__snapshots__/paste/parse-nested-lists-with-paragraphs.json +132 -7
- package/src/api/parsers/html/__snapshots__/paste/parse-nested-lists.json +111 -3
- package/src/api/parsers/html/parseHTML.test.ts +166 -95
- package/src/api/testUtil/cases/customBlocks.ts +3 -0
- package/src/api/testUtil/cases/defaultSchema.ts +71 -0
- package/src/blocks/AudioBlockContent/AudioBlockContent.ts +3 -2
- package/src/blocks/FileBlockContent/FileBlockContent.ts +1 -2
- package/src/blocks/ImageBlockContent/ImageBlockContent.ts +3 -2
- package/src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts +3 -0
- package/src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.ts +266 -0
- package/src/blocks/ListItemBlockContent/ListItemKeyboardShortcuts.ts +2 -1
- package/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts +1 -0
- package/src/blocks/VideoBlockContent/VideoBlockContent.ts +0 -1
- package/src/blocks/defaultBlockTypeGuards.ts +1 -1
- package/src/blocks/defaultBlocks.ts +6 -3
- package/src/editor/Block.css +22 -0
- package/src/editor/BlockNoteEditor.ts +10 -0
- package/src/editor/transformPasted.ts +2 -1
- package/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts +13 -0
- package/src/extensions/TableHandles/TableHandlesPlugin.ts +27 -27
- package/src/extensions/TextAlignment/TextAlignmentExtension.ts +7 -1
- package/src/i18n/locales/en.ts +15 -0
- package/src/i18n/locales/fr.ts +14 -0
- package/src/i18n/locales/is.ts +7 -0
- package/src/i18n/locales/ja.ts +24 -1
- package/src/i18n/locales/ko.ts +15 -0
- package/src/i18n/locales/nl.ts +7 -0
- package/src/i18n/locales/pl.ts +7 -0
- package/src/i18n/locales/pt.ts +14 -0
- package/src/i18n/locales/vi.ts +16 -2
- package/src/i18n/locales/zh.ts +16 -0
- package/src/pm-nodes/BlockContainer.ts +16 -4
- package/src/schema/blocks/types.ts +0 -1
- package/types/src/api/exporters/markdown/util/addSpacesToCheckboxesRehypePlugin.d.ts +7 -0
- package/types/src/api/testUtil/cases/customBlocks.d.ts +74 -42
- package/types/src/api/testUtil/cases/customInlineContent.d.ts +74 -42
- package/types/src/api/testUtil/cases/customStyles.d.ts +74 -42
- package/types/src/blocks/AudioBlockContent/AudioBlockContent.d.ts +0 -3
- package/types/src/blocks/FileBlockContent/FileBlockContent.d.ts +0 -3
- package/types/src/blocks/ImageBlockContent/ImageBlockContent.d.ts +0 -3
- package/types/src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.d.ts +55 -0
- package/types/src/blocks/VideoBlockContent/VideoBlockContent.d.ts +0 -3
- package/types/src/blocks/defaultBlocks.d.ts +141 -77
- package/types/src/editor/BlockNoteEditor.d.ts +7 -0
- package/types/src/extensions/TableHandles/TableHandlesPlugin.d.ts +1 -1
- package/types/src/i18n/locales/en.d.ts +7 -0
- package/types/src/pm-nodes/BlockContainer.d.ts +1 -1
- package/types/src/schema/blocks/types.d.ts +0 -1
package/src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.ts
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { InputRule } from "@tiptap/core";
|
|
2
|
+
import {
|
|
3
|
+
PropSchema,
|
|
4
|
+
createBlockSpecFromStronglyTypedTiptapNode,
|
|
5
|
+
createStronglyTypedTiptapNode,
|
|
6
|
+
} from "../../../schema";
|
|
7
|
+
import { createDefaultBlockDOMOutputSpec } from "../../defaultBlockHelpers";
|
|
8
|
+
import { defaultProps } from "../../defaultProps";
|
|
9
|
+
import { handleEnter } from "../ListItemKeyboardShortcuts";
|
|
10
|
+
import { getCurrentBlockContentType } from "../../../api/getCurrentBlockContentType";
|
|
11
|
+
|
|
12
|
+
export const checkListItemPropSchema = {
|
|
13
|
+
...defaultProps,
|
|
14
|
+
checked: {
|
|
15
|
+
default: false,
|
|
16
|
+
},
|
|
17
|
+
} satisfies PropSchema;
|
|
18
|
+
|
|
19
|
+
const checkListItemBlockContent = createStronglyTypedTiptapNode({
|
|
20
|
+
name: "checkListItem",
|
|
21
|
+
content: "inline*",
|
|
22
|
+
group: "blockContent",
|
|
23
|
+
addAttributes() {
|
|
24
|
+
return {
|
|
25
|
+
checked: {
|
|
26
|
+
default: false,
|
|
27
|
+
// instead of "checked" attributes, use "data-checked"
|
|
28
|
+
parseHTML: (element) =>
|
|
29
|
+
element.getAttribute("data-checked") === "true" || undefined,
|
|
30
|
+
renderHTML: (attributes) => {
|
|
31
|
+
return attributes.checked
|
|
32
|
+
? {
|
|
33
|
+
"data-checked": (attributes.checked as boolean).toString(),
|
|
34
|
+
}
|
|
35
|
+
: {};
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
addInputRules() {
|
|
42
|
+
return [
|
|
43
|
+
// Creates a checklist when starting with "[]" or "[X]".
|
|
44
|
+
new InputRule({
|
|
45
|
+
find: new RegExp(`\\[\\s*\\]\\s$`),
|
|
46
|
+
handler: ({ state, chain, range }) => {
|
|
47
|
+
if (getCurrentBlockContentType(this.editor) !== "inline*") {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
chain()
|
|
52
|
+
.BNUpdateBlock(state.selection.from, {
|
|
53
|
+
type: "checkListItem",
|
|
54
|
+
props: {
|
|
55
|
+
checked: false as any,
|
|
56
|
+
},
|
|
57
|
+
})
|
|
58
|
+
// Removes the characters used to set the list.
|
|
59
|
+
.deleteRange({ from: range.from, to: range.to });
|
|
60
|
+
},
|
|
61
|
+
}),
|
|
62
|
+
new InputRule({
|
|
63
|
+
find: new RegExp(`\\[[Xx]\\]\\s$`),
|
|
64
|
+
handler: ({ state, chain, range }) => {
|
|
65
|
+
if (getCurrentBlockContentType(this.editor) !== "inline*") {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
chain()
|
|
70
|
+
.BNUpdateBlock(state.selection.from, {
|
|
71
|
+
type: "checkListItem",
|
|
72
|
+
props: {
|
|
73
|
+
checked: true as any,
|
|
74
|
+
},
|
|
75
|
+
})
|
|
76
|
+
// Removes the characters used to set the list.
|
|
77
|
+
.deleteRange({ from: range.from, to: range.to });
|
|
78
|
+
},
|
|
79
|
+
}),
|
|
80
|
+
];
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
addKeyboardShortcuts() {
|
|
84
|
+
return {
|
|
85
|
+
Enter: () => handleEnter(this.editor),
|
|
86
|
+
"Mod-Shift-9": () => {
|
|
87
|
+
if (getCurrentBlockContentType(this.editor) !== "inline*") {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return this.editor.commands.BNUpdateBlock(
|
|
92
|
+
this.editor.state.selection.anchor,
|
|
93
|
+
{
|
|
94
|
+
type: "checkListItem",
|
|
95
|
+
props: {},
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
parseHTML() {
|
|
103
|
+
return [
|
|
104
|
+
{
|
|
105
|
+
tag: "div[data-content-type=" + this.name + "]", // TODO: remove if we can't come up with test case that needs this
|
|
106
|
+
},
|
|
107
|
+
// Checkbox only.
|
|
108
|
+
{
|
|
109
|
+
tag: "input",
|
|
110
|
+
getAttrs: (element) => {
|
|
111
|
+
if (typeof element === "string") {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if ((element as HTMLInputElement).type === "checkbox") {
|
|
116
|
+
return { checked: (element as HTMLInputElement).checked };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return false;
|
|
120
|
+
},
|
|
121
|
+
node: "checkListItem",
|
|
122
|
+
},
|
|
123
|
+
// Container element for checkbox + label.
|
|
124
|
+
{
|
|
125
|
+
tag: "li",
|
|
126
|
+
getAttrs: (element) => {
|
|
127
|
+
if (typeof element === "string") {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const parent = element.parentElement;
|
|
132
|
+
|
|
133
|
+
if (parent === null) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (
|
|
138
|
+
parent.tagName === "UL" ||
|
|
139
|
+
(parent.tagName === "DIV" && parent.parentElement!.tagName === "UL")
|
|
140
|
+
) {
|
|
141
|
+
const checkbox =
|
|
142
|
+
(element.querySelector(
|
|
143
|
+
"input[type=checkbox]"
|
|
144
|
+
) as HTMLInputElement) || null;
|
|
145
|
+
|
|
146
|
+
if (checkbox === null) {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return { checked: checkbox.checked };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return false;
|
|
154
|
+
},
|
|
155
|
+
node: "checkListItem",
|
|
156
|
+
},
|
|
157
|
+
];
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
// Since there is no HTML checklist element, there isn't really any
|
|
161
|
+
// standardization for what checklists should look like in the DOM. GDocs'
|
|
162
|
+
// and Notion's aren't cross compatible, for example. This implementation
|
|
163
|
+
// has a semantically correct DOM structure (though missing a label for the
|
|
164
|
+
// checkbox) which is also converted correctly to Markdown by remark.
|
|
165
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
166
|
+
const checkbox = document.createElement("input");
|
|
167
|
+
checkbox.type = "checkbox";
|
|
168
|
+
checkbox.checked = node.attrs.checked;
|
|
169
|
+
if (node.attrs.checked) {
|
|
170
|
+
checkbox.setAttribute("checked", "");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const { dom, contentDOM } = createDefaultBlockDOMOutputSpec(
|
|
174
|
+
this.name,
|
|
175
|
+
"p",
|
|
176
|
+
{
|
|
177
|
+
...(this.options.domAttributes?.blockContent || {}),
|
|
178
|
+
...HTMLAttributes,
|
|
179
|
+
},
|
|
180
|
+
this.options.domAttributes?.inlineContent || {}
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
dom.insertBefore(checkbox, contentDOM);
|
|
184
|
+
|
|
185
|
+
return { dom, contentDOM };
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
// Need to render node view since the checkbox needs to be able to update the
|
|
189
|
+
// node. This is only possible with a node view as it exposes `getPos`.
|
|
190
|
+
addNodeView() {
|
|
191
|
+
return ({ node, getPos, editor, HTMLAttributes }) => {
|
|
192
|
+
// Need to wrap certain elements in a div or keyboard navigation gets
|
|
193
|
+
// confused.
|
|
194
|
+
const wrapper = document.createElement("div");
|
|
195
|
+
const checkboxWrapper = document.createElement("div");
|
|
196
|
+
checkboxWrapper.contentEditable = "false";
|
|
197
|
+
|
|
198
|
+
const checkbox = document.createElement("input");
|
|
199
|
+
checkbox.type = "checkbox";
|
|
200
|
+
checkbox.checked = node.attrs.checked;
|
|
201
|
+
if (node.attrs.checked) {
|
|
202
|
+
checkbox.setAttribute("checked", "");
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const changeHandler = () => {
|
|
206
|
+
if (!editor.isEditable) {
|
|
207
|
+
// This seems like the most effective way of blocking the checkbox
|
|
208
|
+
// from being toggled, as event.preventDefault() does not stop it for
|
|
209
|
+
// "click" or "change" events.
|
|
210
|
+
checkbox.checked = !checkbox.checked;
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (typeof getPos !== "boolean") {
|
|
215
|
+
this.editor.commands.BNUpdateBlock(getPos(), {
|
|
216
|
+
type: "checkListItem",
|
|
217
|
+
props: {
|
|
218
|
+
checked: checkbox.checked as any,
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
checkbox.addEventListener("change", changeHandler);
|
|
224
|
+
|
|
225
|
+
const { dom, contentDOM } = createDefaultBlockDOMOutputSpec(
|
|
226
|
+
this.name,
|
|
227
|
+
"p",
|
|
228
|
+
{
|
|
229
|
+
...(this.options.domAttributes?.blockContent || {}),
|
|
230
|
+
...HTMLAttributes,
|
|
231
|
+
},
|
|
232
|
+
this.options.domAttributes?.inlineContent || {}
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
if (typeof getPos !== "boolean") {
|
|
236
|
+
// Since `node` is a blockContent node, we have to get the block ID from
|
|
237
|
+
// the parent blockContainer node. This means we can't add the label in
|
|
238
|
+
// `renderHTML` as we can't use `getPos` and therefore can't get the
|
|
239
|
+
// parent blockContainer node.
|
|
240
|
+
const blockID = this.editor.state.doc.resolve(getPos()).node().attrs.id;
|
|
241
|
+
const label = "label-" + blockID;
|
|
242
|
+
checkbox.setAttribute("aria-labelledby", label);
|
|
243
|
+
contentDOM.id = label;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
dom.removeChild(contentDOM);
|
|
247
|
+
dom.appendChild(wrapper);
|
|
248
|
+
wrapper.appendChild(checkboxWrapper);
|
|
249
|
+
wrapper.appendChild(contentDOM);
|
|
250
|
+
checkboxWrapper.appendChild(checkbox);
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
dom,
|
|
254
|
+
contentDOM,
|
|
255
|
+
destroy: () => {
|
|
256
|
+
checkbox.removeEventListener("change", changeHandler);
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
};
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
export const CheckListItem = createBlockSpecFromStronglyTypedTiptapNode(
|
|
264
|
+
checkListItemBlockContent,
|
|
265
|
+
checkListItemPropSchema
|
|
266
|
+
);
|
|
@@ -13,7 +13,8 @@ export const handleEnter = (editor: Editor) => {
|
|
|
13
13
|
if (
|
|
14
14
|
!(
|
|
15
15
|
contentType.name === "bulletListItem" ||
|
|
16
|
-
contentType.name === "numberedListItem"
|
|
16
|
+
contentType.name === "numberedListItem" ||
|
|
17
|
+
contentType.name === "checkListItem"
|
|
17
18
|
) ||
|
|
18
19
|
!selectionEmpty
|
|
19
20
|
) {
|
|
@@ -82,7 +82,7 @@ export function checkBlockIsFileBlockWithPlaceholder<
|
|
|
82
82
|
S extends StyleSchema
|
|
83
83
|
>(block: Block<B, I, S>, editor: BlockNoteEditor<B, I, S>) {
|
|
84
84
|
const config = editor.schema.blockSchema[block.type];
|
|
85
|
-
return config.isFileBlock &&
|
|
85
|
+
return config.isFileBlock && !block.props.url;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
export function checkBlockTypeHasDefaultProp<
|
|
@@ -19,13 +19,15 @@ import {
|
|
|
19
19
|
getInlineContentSchemaFromSpecs,
|
|
20
20
|
getStyleSchemaFromSpecs,
|
|
21
21
|
} from "../schema";
|
|
22
|
-
|
|
23
|
-
import { ImageBlock } from "./ImageBlockContent/ImageBlockContent";
|
|
22
|
+
|
|
24
23
|
import { Heading } from "./HeadingBlockContent/HeadingBlockContent";
|
|
25
24
|
import { BulletListItem } from "./ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent";
|
|
26
25
|
import { NumberedListItem } from "./ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent";
|
|
26
|
+
import { CheckListItem } from "./ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent";
|
|
27
27
|
import { Paragraph } from "./ParagraphBlockContent/ParagraphBlockContent";
|
|
28
28
|
import { Table } from "./TableBlockContent/TableBlockContent";
|
|
29
|
+
import { FileBlock } from "./FileBlockContent/FileBlockContent";
|
|
30
|
+
import { ImageBlock } from "./ImageBlockContent/ImageBlockContent";
|
|
29
31
|
import { VideoBlock } from "./VideoBlockContent/VideoBlockContent";
|
|
30
32
|
import { AudioBlock } from "./AudioBlockContent/AudioBlockContent";
|
|
31
33
|
|
|
@@ -34,11 +36,12 @@ export const defaultBlockSpecs = {
|
|
|
34
36
|
heading: Heading,
|
|
35
37
|
bulletListItem: BulletListItem,
|
|
36
38
|
numberedListItem: NumberedListItem,
|
|
39
|
+
checkListItem: CheckListItem,
|
|
40
|
+
table: Table,
|
|
37
41
|
file: FileBlock,
|
|
38
42
|
image: ImageBlock,
|
|
39
43
|
video: VideoBlock,
|
|
40
44
|
audio: AudioBlock,
|
|
41
|
-
table: Table,
|
|
42
45
|
} satisfies BlockSpecs;
|
|
43
46
|
|
|
44
47
|
export const defaultBlockSchema = getBlockSchemaFromSpecs(defaultBlockSpecs);
|
package/src/editor/Block.css
CHANGED
|
@@ -185,6 +185,28 @@ NESTED BLOCKS
|
|
|
185
185
|
gap: 1.2em;
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
/* Checked */
|
|
189
|
+
.bn-block-content[data-content-type="checkListItem"] > div {
|
|
190
|
+
display: flex;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.bn-block-content[data-content-type="checkListItem"] > div > div > input {
|
|
194
|
+
margin: 0 1.2em 0 0;
|
|
195
|
+
cursor: pointer;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.bn-block-content[data-content-type="checkListItem"][data-checked="true"] .bn-inline-content {
|
|
199
|
+
text-decoration: line-through;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.bn-block-content[data-text-alignment="center"] {
|
|
203
|
+
justify-content: center;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.bn-block-content[data-text-alignment="right"] {
|
|
207
|
+
justify-content: flex-end;
|
|
208
|
+
}
|
|
209
|
+
|
|
188
210
|
/* No list nesting */
|
|
189
211
|
.bn-block-outer[data-prev-type="bulletListItem"]
|
|
190
212
|
> .bn-block
|
|
@@ -117,6 +117,13 @@ export type BlockNoteEditorOptions<
|
|
|
117
117
|
*/
|
|
118
118
|
uploadFile: (file: File) => Promise<string | Record<string, any>>;
|
|
119
119
|
|
|
120
|
+
/**
|
|
121
|
+
* Resolve a URL of a file block to one that can be displayed or downloaded. This can be used for creating authenticated URL or
|
|
122
|
+
* implementing custom protocols / schemes
|
|
123
|
+
* @returns The URL that's
|
|
124
|
+
*/
|
|
125
|
+
resolveFileUrl: (url: string) => Promise<string>;
|
|
126
|
+
|
|
120
127
|
/**
|
|
121
128
|
* When enabled, allows for collaboration between multiple users.
|
|
122
129
|
*/
|
|
@@ -201,6 +208,8 @@ export class BlockNoteEditor<
|
|
|
201
208
|
| ((file: File) => Promise<string | Record<string, any>>)
|
|
202
209
|
| undefined;
|
|
203
210
|
|
|
211
|
+
public readonly resolveFileUrl: (url: string) => Promise<string>;
|
|
212
|
+
|
|
204
213
|
public static create<
|
|
205
214
|
BSchema extends BlockSchema = DefaultBlockSchema,
|
|
206
215
|
ISchema extends InlineContentSchema = DefaultInlineContentSchema,
|
|
@@ -295,6 +304,7 @@ export class BlockNoteEditor<
|
|
|
295
304
|
extensions.push(blockNoteUIExtension);
|
|
296
305
|
|
|
297
306
|
this.uploadFile = newOptions.uploadFile;
|
|
307
|
+
this.resolveFileUrl = newOptions.resolveFileUrl || (async (url) => url);
|
|
298
308
|
|
|
299
309
|
if (newOptions.collaboration && newOptions.initialContent) {
|
|
300
310
|
console.warn(
|
|
@@ -40,7 +40,8 @@ export function transformPasted(slice: Slice, view: EditorView) {
|
|
|
40
40
|
|
|
41
41
|
if (
|
|
42
42
|
nestedChild.type.name === "bulletListItem" ||
|
|
43
|
-
nestedChild.type.name === "numberedListItem"
|
|
43
|
+
nestedChild.type.name === "numberedListItem" ||
|
|
44
|
+
nestedChild.type.name === "checkListItem"
|
|
44
45
|
) {
|
|
45
46
|
content.push(f.child(i + 1));
|
|
46
47
|
f = removeChild(f, i + 1);
|
|
@@ -144,6 +144,19 @@ export function getDefaultSlashMenuItems<
|
|
|
144
144
|
});
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
if (checkDefaultBlockTypeInSchema("checkListItem", editor)) {
|
|
148
|
+
items.push({
|
|
149
|
+
onItemClick: () => {
|
|
150
|
+
insertOrUpdateBlock(editor, {
|
|
151
|
+
type: "checkListItem",
|
|
152
|
+
});
|
|
153
|
+
},
|
|
154
|
+
badge: formatKeyboardShortcut("Mod-Shift-9"),
|
|
155
|
+
key: "check_list",
|
|
156
|
+
...editor.dictionary.slash_menu.check_list,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
147
160
|
if (checkDefaultBlockTypeInSchema("paragraph", editor)) {
|
|
148
161
|
items.push({
|
|
149
162
|
onItemClick: () => {
|
|
@@ -7,9 +7,9 @@ import {
|
|
|
7
7
|
BlockFromConfigNoChildren,
|
|
8
8
|
BlockSchemaWithBlock,
|
|
9
9
|
InlineContentSchema,
|
|
10
|
-
SpecificBlock,
|
|
11
10
|
StyleSchema,
|
|
12
11
|
} from "../../schema";
|
|
12
|
+
import { checkBlockIsDefaultType } from "../../blocks/defaultBlockTypeGuards";
|
|
13
13
|
import { EventEmitter } from "../../util/EventEmitter";
|
|
14
14
|
import { getDraggableBlockFromCoords } from "../SideMenu/SideMenuPlugin";
|
|
15
15
|
|
|
@@ -83,7 +83,6 @@ function hideElementsWithClassNames(classNames: string[]) {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
export class TableHandlesView<
|
|
86
|
-
BSchema extends BlockSchemaWithBlock<"table", DefaultBlockSchema["table"]>,
|
|
87
86
|
I extends InlineContentSchema,
|
|
88
87
|
S extends StyleSchema
|
|
89
88
|
> implements PluginView
|
|
@@ -146,28 +145,15 @@ export class TableHandlesView<
|
|
|
146
145
|
|
|
147
146
|
const blockEl = getDraggableBlockFromCoords(cellRect, this.pmView);
|
|
148
147
|
if (!blockEl) {
|
|
149
|
-
throw new Error(
|
|
150
|
-
"Found table cell element, but could not find surrounding blockContent element."
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
this.tableId = blockEl.id;
|
|
154
|
-
|
|
155
|
-
if (
|
|
156
|
-
this.state !== undefined &&
|
|
157
|
-
this.state.show &&
|
|
158
|
-
this.tableId === blockEl.id &&
|
|
159
|
-
this.state.rowIndex === rowIndex &&
|
|
160
|
-
this.state.colIndex === colIndex
|
|
161
|
-
) {
|
|
162
148
|
return;
|
|
163
149
|
}
|
|
164
150
|
|
|
165
|
-
let
|
|
151
|
+
let tableBlock: Block<any, any, any> | undefined = undefined;
|
|
166
152
|
|
|
167
153
|
// Copied from `getBlock`. We don't use `getBlock` since we also need the PM
|
|
168
154
|
// node for the table, so we would effectively be doing the same work twice.
|
|
169
155
|
this.editor._tiptapEditor.state.doc.descendants((node, pos) => {
|
|
170
|
-
if (typeof
|
|
156
|
+
if (typeof tableBlock !== "undefined") {
|
|
171
157
|
return false;
|
|
172
158
|
}
|
|
173
159
|
|
|
@@ -175,24 +161,44 @@ export class TableHandlesView<
|
|
|
175
161
|
return true;
|
|
176
162
|
}
|
|
177
163
|
|
|
178
|
-
block = nodeToBlock(
|
|
164
|
+
const block = nodeToBlock(
|
|
179
165
|
node,
|
|
180
166
|
this.editor.schema.blockSchema,
|
|
181
167
|
this.editor.schema.inlineContentSchema,
|
|
182
168
|
this.editor.schema.styleSchema,
|
|
183
169
|
this.editor.blockCache
|
|
184
170
|
);
|
|
185
|
-
|
|
171
|
+
|
|
172
|
+
if (checkBlockIsDefaultType("table", block, this.editor)) {
|
|
173
|
+
this.tablePos = pos + 1;
|
|
174
|
+
tableBlock = block;
|
|
175
|
+
}
|
|
186
176
|
|
|
187
177
|
return false;
|
|
188
178
|
});
|
|
189
179
|
|
|
180
|
+
if (!tableBlock) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
this.tableId = blockEl.id;
|
|
185
|
+
|
|
186
|
+
if (
|
|
187
|
+
this.state !== undefined &&
|
|
188
|
+
this.state.show &&
|
|
189
|
+
this.tableId === blockEl.id &&
|
|
190
|
+
this.state.rowIndex === rowIndex &&
|
|
191
|
+
this.state.colIndex === colIndex
|
|
192
|
+
) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
190
196
|
this.state = {
|
|
191
197
|
show: true,
|
|
192
198
|
referencePosCell: cellRect,
|
|
193
199
|
referencePosTable: tableRect,
|
|
194
200
|
|
|
195
|
-
block:
|
|
201
|
+
block: tableBlock,
|
|
196
202
|
colIndex: colIndex,
|
|
197
203
|
rowIndex: rowIndex,
|
|
198
204
|
|
|
@@ -365,13 +371,7 @@ export class TableHandlesProsemirrorPlugin<
|
|
|
365
371
|
I extends InlineContentSchema,
|
|
366
372
|
S extends StyleSchema
|
|
367
373
|
> extends EventEmitter<any> {
|
|
368
|
-
private view:
|
|
369
|
-
| TableHandlesView<
|
|
370
|
-
BlockSchemaWithBlock<"table", DefaultBlockSchema["table"]>,
|
|
371
|
-
I,
|
|
372
|
-
S
|
|
373
|
-
>
|
|
374
|
-
| undefined;
|
|
374
|
+
private view: TableHandlesView<I, S> | undefined;
|
|
375
375
|
public readonly plugin: Plugin;
|
|
376
376
|
|
|
377
377
|
constructor(
|
|
@@ -8,7 +8,13 @@ export const TextAlignmentExtension = Extension.create({
|
|
|
8
8
|
{
|
|
9
9
|
// Attribute is applied to block content instead of container so that child blocks don't inherit the text
|
|
10
10
|
// alignment styling.
|
|
11
|
-
types: [
|
|
11
|
+
types: [
|
|
12
|
+
"paragraph",
|
|
13
|
+
"heading",
|
|
14
|
+
"bulletListItem",
|
|
15
|
+
"numberedListItem",
|
|
16
|
+
"checkListItem",
|
|
17
|
+
],
|
|
12
18
|
attributes: {
|
|
13
19
|
textAlignment: {
|
|
14
20
|
default: "left",
|
package/src/i18n/locales/en.ts
CHANGED
|
@@ -30,6 +30,20 @@ export const en = {
|
|
|
30
30
|
aliases: ["ul", "li", "list", "bulletlist", "bullet list"],
|
|
31
31
|
group: "Basic blocks",
|
|
32
32
|
},
|
|
33
|
+
check_list: {
|
|
34
|
+
title: "Check List",
|
|
35
|
+
subtext: "Used to display a list with checkboxes",
|
|
36
|
+
aliases: [
|
|
37
|
+
"ul",
|
|
38
|
+
"li",
|
|
39
|
+
"list",
|
|
40
|
+
"checklist",
|
|
41
|
+
"check list",
|
|
42
|
+
"checked list",
|
|
43
|
+
"checkbox",
|
|
44
|
+
],
|
|
45
|
+
group: "Basic blocks",
|
|
46
|
+
},
|
|
33
47
|
paragraph: {
|
|
34
48
|
title: "Paragraph",
|
|
35
49
|
subtext: "Used for the body of your document",
|
|
@@ -96,6 +110,7 @@ export const en = {
|
|
|
96
110
|
heading: "Heading",
|
|
97
111
|
bulletListItem: "List",
|
|
98
112
|
numberedListItem: "List",
|
|
113
|
+
checkListItem: "List",
|
|
99
114
|
},
|
|
100
115
|
file_blocks: {
|
|
101
116
|
image: {
|
package/src/i18n/locales/fr.ts
CHANGED
|
@@ -32,6 +32,19 @@ export const fr: Dictionary = {
|
|
|
32
32
|
aliases: ["ul", "li", "liste", "listeàpuces", "liste à puces"],
|
|
33
33
|
group: "Blocs de base",
|
|
34
34
|
},
|
|
35
|
+
check_list: {
|
|
36
|
+
title: "Liste de vérification",
|
|
37
|
+
subtext: "Utilisé pour afficher une liste avec des cases à cocher",
|
|
38
|
+
aliases: [
|
|
39
|
+
"ul",
|
|
40
|
+
"li",
|
|
41
|
+
"liste",
|
|
42
|
+
"liste de vérification",
|
|
43
|
+
"liste cochée",
|
|
44
|
+
"case à cocher",
|
|
45
|
+
],
|
|
46
|
+
group: "Blocs de base",
|
|
47
|
+
},
|
|
35
48
|
paragraph: {
|
|
36
49
|
title: "Paragraphe",
|
|
37
50
|
subtext: "Utilisé pour le corps de votre document",
|
|
@@ -98,6 +111,7 @@ export const fr: Dictionary = {
|
|
|
98
111
|
heading: "Titre",
|
|
99
112
|
bulletListItem: "Liste",
|
|
100
113
|
numberedListItem: "Liste",
|
|
114
|
+
checkListItem: "Liste",
|
|
101
115
|
},
|
|
102
116
|
file_blocks: {
|
|
103
117
|
image: {
|
package/src/i18n/locales/is.ts
CHANGED
|
@@ -32,6 +32,12 @@ export const is: Dictionary = {
|
|
|
32
32
|
aliases: ["ul", "li", "listi", "punktalisti"],
|
|
33
33
|
group: "Grunnblokkar",
|
|
34
34
|
},
|
|
35
|
+
check_list: {
|
|
36
|
+
title: "Athugunarlisti",
|
|
37
|
+
subtext: "Notað til að sýna lista með gátreitum",
|
|
38
|
+
aliases: ["ul", "li", "listi", "athugunarlisti", "merktur listi"],
|
|
39
|
+
group: "Grunnblokkar",
|
|
40
|
+
},
|
|
35
41
|
paragraph: {
|
|
36
42
|
title: "Málsgrein",
|
|
37
43
|
subtext: "Notað fyrir meginmál skjalsins",
|
|
@@ -98,6 +104,7 @@ export const is: Dictionary = {
|
|
|
98
104
|
heading: "Fyrirsögn",
|
|
99
105
|
bulletListItem: "Listi",
|
|
100
106
|
numberedListItem: "Listi",
|
|
107
|
+
checkListItem: "Listi",
|
|
101
108
|
},
|
|
102
109
|
file_blocks: {
|
|
103
110
|
image: {
|
package/src/i18n/locales/ja.ts
CHANGED
|
@@ -37,7 +37,29 @@ export const ja: Dictionary = {
|
|
|
37
37
|
bullet_list: {
|
|
38
38
|
title: "箇条書き",
|
|
39
39
|
subtext: "箇条書きを表示するために使用",
|
|
40
|
-
aliases: [
|
|
40
|
+
aliases: [
|
|
41
|
+
"ul",
|
|
42
|
+
"li",
|
|
43
|
+
"bulletlist",
|
|
44
|
+
"bullet list",
|
|
45
|
+
"リスト",
|
|
46
|
+
"箇条書きリスト",
|
|
47
|
+
],
|
|
48
|
+
group: "基本ブロック",
|
|
49
|
+
},
|
|
50
|
+
check_list: {
|
|
51
|
+
title: "チェックリスト",
|
|
52
|
+
subtext: "チェックボックス付きリストを表示するために使用されます",
|
|
53
|
+
aliases: [
|
|
54
|
+
"ul",
|
|
55
|
+
"li",
|
|
56
|
+
"list",
|
|
57
|
+
"checklist",
|
|
58
|
+
"checked list",
|
|
59
|
+
"リスト",
|
|
60
|
+
"チェックリスト",
|
|
61
|
+
"チェックされたリスト",
|
|
62
|
+
],
|
|
41
63
|
group: "基本ブロック",
|
|
42
64
|
},
|
|
43
65
|
paragraph: {
|
|
@@ -109,6 +131,7 @@ export const ja: Dictionary = {
|
|
|
109
131
|
heading: "見出し",
|
|
110
132
|
bulletListItem: "リストを追加",
|
|
111
133
|
numberedListItem: "リストを追加",
|
|
134
|
+
checkListItem: "リストを追加",
|
|
112
135
|
},
|
|
113
136
|
file_blocks: {
|
|
114
137
|
image: {
|