@blocknote/core 0.13.2 → 0.13.3
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 +5282 -2785
- package/dist/blocknote.js.map +1 -1
- package/dist/blocknote.umd.cjs +7 -7
- 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__/file/basic/external.html +1 -0
- package/src/api/exporters/html/__snapshots__/file/basic/internal.html +1 -0
- package/src/api/exporters/html/__snapshots__/file/button/external.html +1 -0
- package/src/api/exporters/html/__snapshots__/file/button/internal.html +1 -0
- package/src/api/exporters/html/__snapshots__/file/nested/external.html +1 -0
- package/src/api/exporters/html/__snapshots__/file/nested/internal.html +1 -0
- package/src/api/exporters/html/__snapshots__/file/noCaption/external.html +1 -0
- package/src/api/exporters/html/__snapshots__/file/noCaption/internal.html +1 -0
- package/src/api/exporters/html/__snapshots__/file/noName/external.html +1 -0
- package/src/api/exporters/html/__snapshots__/file/noName/internal.html +1 -0
- package/src/api/exporters/html/__snapshots__/image/basic/external.html +1 -1
- package/src/api/exporters/html/__snapshots__/image/basic/internal.html +1 -1
- package/src/api/exporters/html/__snapshots__/image/button/external.html +1 -1
- package/src/api/exporters/html/__snapshots__/image/button/internal.html +1 -1
- package/src/api/exporters/html/__snapshots__/image/nested/external.html +1 -1
- package/src/api/exporters/html/__snapshots__/image/nested/internal.html +1 -1
- package/src/api/exporters/html/__snapshots__/image/noCaption/external.html +1 -0
- package/src/api/exporters/html/__snapshots__/image/noCaption/internal.html +1 -0
- package/src/api/exporters/html/__snapshots__/image/noName/external.html +1 -0
- package/src/api/exporters/html/__snapshots__/image/noName/internal.html +1 -0
- package/src/api/exporters/html/__snapshots__/image/noPreview/external.html +1 -0
- package/src/api/exporters/html/__snapshots__/image/noPreview/internal.html +1 -0
- package/src/api/exporters/html/__snapshots__/simpleFile/basic/external.html +1 -0
- package/src/api/exporters/html/__snapshots__/simpleFile/basic/internal.html +1 -0
- package/src/api/exporters/html/__snapshots__/simpleFile/button/external.html +1 -0
- package/src/api/exporters/html/__snapshots__/simpleFile/button/internal.html +1 -0
- package/src/api/exporters/html/__snapshots__/simpleFile/nested/external.html +1 -0
- package/src/api/exporters/html/__snapshots__/simpleFile/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/button/external.html +1 -1
- package/src/api/exporters/html/__snapshots__/simpleImage/button/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 -0
- package/src/api/exporters/html/__snapshots__/simpleImage/noCaption/internal.html +1 -0
- package/src/api/exporters/html/__snapshots__/simpleImage/noName/external.html +1 -0
- package/src/api/exporters/html/__snapshots__/simpleImage/noName/internal.html +1 -0
- package/src/api/exporters/html/__snapshots__/simpleImage/noPreview/external.html +1 -0
- package/src/api/exporters/html/__snapshots__/simpleImage/noPreview/internal.html +1 -0
- package/src/api/exporters/markdown/__snapshots__/file/basic/markdown.md +3 -0
- package/src/api/exporters/markdown/__snapshots__/file/button/markdown.md +1 -0
- package/src/api/exporters/markdown/__snapshots__/file/nested/markdown.md +7 -0
- package/src/api/exporters/markdown/__snapshots__/file/noCaption/markdown.md +1 -0
- package/src/api/exporters/markdown/__snapshots__/file/noName/markdown.md +3 -0
- package/src/api/exporters/markdown/__snapshots__/image/basic/markdown.md +1 -1
- package/src/api/exporters/markdown/__snapshots__/image/button/markdown.md +1 -1
- package/src/api/exporters/markdown/__snapshots__/image/nested/markdown.md +2 -2
- package/src/api/exporters/markdown/__snapshots__/image/noCaption/markdown.md +1 -0
- package/src/api/exporters/markdown/__snapshots__/image/noName/markdown.md +3 -0
- package/src/api/exporters/markdown/__snapshots__/image/noPreview/markdown.md +3 -0
- package/src/api/exporters/markdown/__snapshots__/simpleFile/basic/markdown.md +3 -0
- package/src/api/exporters/markdown/__snapshots__/simpleFile/button/markdown.md +1 -0
- package/src/api/exporters/markdown/__snapshots__/simpleFile/nested/markdown.md +7 -0
- package/src/api/exporters/markdown/__snapshots__/simpleImage/basic/markdown.md +3 -1
- package/src/api/exporters/markdown/__snapshots__/simpleImage/button/markdown.md +1 -0
- package/src/api/exporters/markdown/__snapshots__/simpleImage/nested/markdown.md +6 -2
- package/src/api/exporters/markdown/__snapshots__/simpleImage/noCaption/markdown.md +1 -0
- package/src/api/exporters/markdown/__snapshots__/simpleImage/noName/markdown.md +3 -0
- package/src/api/exporters/markdown/__snapshots__/simpleImage/noPreview/markdown.md +3 -0
- package/src/api/nodeConversions/__snapshots__/nodeConversions.test.ts.snap +212 -4
- package/src/api/parsers/html/__snapshots__/paste/parse-basic-block-types.json +3 -1
- package/src/api/parsers/html/__snapshots__/paste/parse-fake-image-caption.json +3 -1
- package/src/api/testUtil/cases/customBlocks.ts +79 -33
- package/src/api/testUtil/cases/customInlineContent.ts +1 -1
- package/src/api/testUtil/cases/customStyles.ts +1 -1
- package/src/api/testUtil/cases/defaultSchema.ts +114 -4
- package/src/blocks/AudioBlockContent/AudioBlockContent.ts +162 -0
- package/src/blocks/AudioBlockContent/audioBlockHelpers.ts +5 -0
- package/src/blocks/FileBlockContent/FileBlockContent.ts +121 -0
- package/src/blocks/FileBlockContent/fileBlockHelpers.ts +377 -0
- package/src/blocks/ImageBlockContent/ImageBlockContent.ts +135 -356
- package/src/blocks/ImageBlockContent/imageBlockHelpers.ts +6 -0
- package/src/blocks/VideoBlockContent/VideoBlockContent.ts +182 -0
- package/src/blocks/VideoBlockContent/videoBlockHelpers.ts +6 -0
- package/src/blocks/defaultBlockTypeGuards.ts +53 -1
- package/src/blocks/defaultBlocks.ts +8 -2
- package/src/editor/Block.css +67 -27
- package/src/editor/BlockNoteEditor.ts +14 -10
- package/src/editor/BlockNoteSchema.ts +12 -3
- package/src/extensions/{ImagePanel/ImageToolbarPlugin.ts → FilePanel/FilePanelPlugin.ts} +22 -25
- package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +14 -2
- package/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts +59 -2
- package/src/i18n/locales/en.ts +102 -11
- package/src/i18n/locales/fr.ts +104 -11
- package/src/i18n/locales/index.ts +8 -2
- package/src/i18n/locales/is.ts +288 -0
- package/src/i18n/locales/ja.ts +300 -0
- package/src/i18n/locales/ko.ts +292 -0
- package/src/i18n/locales/nl.ts +101 -8
- package/src/i18n/locales/pl.ts +280 -0
- package/src/i18n/locales/pt.ts +281 -0
- package/src/i18n/locales/vi.ts +281 -0
- package/src/i18n/locales/zh.ts +107 -8
- package/src/index.ts +9 -2
- package/src/pm-nodes/BlockContainer.ts +2 -2
- package/src/schema/blocks/createSpec.ts +1 -0
- package/src/schema/blocks/internal.ts +10 -0
- package/src/schema/blocks/types.ts +41 -5
- package/src/util/string.ts +12 -0
- package/types/src/api/testUtil/cases/customBlocks.d.ts +228 -42
- package/types/src/api/testUtil/cases/customInlineContent.d.ts +178 -4
- package/types/src/api/testUtil/cases/customStyles.d.ts +178 -4
- package/types/src/blocks/AudioBlockContent/AudioBlockContent.d.ts +104 -0
- package/types/src/blocks/AudioBlockContent/audioBlockHelpers.d.ts +3 -0
- package/types/src/blocks/FileBlockContent/FileBlockContent.d.ts +96 -0
- package/types/src/blocks/FileBlockContent/fileBlockHelpers.d.ts +30 -0
- package/types/src/blocks/ImageBlockContent/ImageBlockContent.d.ts +53 -14
- package/types/src/blocks/ImageBlockContent/imageBlockHelpers.d.ts +4 -0
- package/types/src/blocks/VideoBlockContent/VideoBlockContent.d.ts +132 -0
- package/types/src/blocks/VideoBlockContent/videoBlockHelpers.d.ts +4 -0
- package/types/src/blocks/defaultBlockTypeGuards.d.ts +6 -1
- package/types/src/blocks/defaultBlocks.d.ts +356 -8
- package/types/src/editor/BlockNoteEditor.d.ts +5 -5
- package/types/src/extensions/{ImagePanel/ImageToolbarPlugin.d.ts → FilePanel/FilePanelPlugin.d.ts} +9 -12
- package/types/src/i18n/locales/en.d.ts +49 -7
- package/types/src/i18n/locales/fr.d.ts +2 -184
- package/types/src/i18n/locales/index.d.ts +7 -1
- package/types/src/i18n/locales/is.d.ts +2 -0
- package/types/src/i18n/locales/ja.d.ts +2 -0
- package/types/src/i18n/locales/ko.d.ts +2 -0
- package/types/src/i18n/locales/pl.d.ts +2 -0
- package/types/src/i18n/locales/pt.d.ts +2 -0
- package/types/src/i18n/locales/vi.d.ts +2 -0
- package/types/src/index.d.ts +8 -2
- package/types/src/schema/blocks/internal.d.ts +1 -1
- package/types/src/schema/blocks/types.d.ts +26 -1
- package/types/src/util/string.d.ts +1 -0
- /package/src/blocks/{ImageBlockContent → FileBlockContent}/uploadToTmpFilesDotOrg_DEV_ONLY.ts +0 -0
- /package/types/src/blocks/{ImageBlockContent → FileBlockContent}/uploadToTmpFilesDotOrg_DEV_ONLY.d.ts +0 -0
|
@@ -1,404 +1,183 @@
|
|
|
1
1
|
import type { BlockNoteEditor } from "../../editor/BlockNoteEditor";
|
|
2
|
-
|
|
3
2
|
import {
|
|
4
3
|
BlockFromConfig,
|
|
5
|
-
BlockSchemaWithBlock,
|
|
6
|
-
CustomBlockConfig,
|
|
7
|
-
InlineContentSchema,
|
|
8
|
-
PropSchema,
|
|
9
|
-
StyleSchema,
|
|
10
4
|
createBlockSpec,
|
|
5
|
+
FileBlockConfig,
|
|
6
|
+
Props,
|
|
7
|
+
PropSchema,
|
|
11
8
|
} from "../../schema";
|
|
12
9
|
import { defaultProps } from "../defaultProps";
|
|
13
10
|
|
|
11
|
+
import {
|
|
12
|
+
createAddFileButton,
|
|
13
|
+
createDefaultFilePreview,
|
|
14
|
+
createFigureWithCaption,
|
|
15
|
+
createFileAndCaptionWrapper,
|
|
16
|
+
createLinkWithCaption,
|
|
17
|
+
createResizeHandlesWrapper,
|
|
18
|
+
parseFigureElement,
|
|
19
|
+
} from "../FileBlockContent/fileBlockHelpers";
|
|
20
|
+
import { parseImageElement } from "./imageBlockHelpers";
|
|
21
|
+
|
|
14
22
|
export const imagePropSchema = {
|
|
15
23
|
textAlignment: defaultProps.textAlignment,
|
|
16
24
|
backgroundColor: defaultProps.backgroundColor,
|
|
17
|
-
//
|
|
25
|
+
// File name.
|
|
26
|
+
name: {
|
|
27
|
+
default: "" as const,
|
|
28
|
+
},
|
|
29
|
+
// File url.
|
|
18
30
|
url: {
|
|
19
31
|
default: "" as const,
|
|
20
32
|
},
|
|
21
|
-
//
|
|
33
|
+
// File caption.
|
|
22
34
|
caption: {
|
|
23
35
|
default: "" as const,
|
|
24
36
|
},
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
default:
|
|
37
|
+
|
|
38
|
+
showPreview: {
|
|
39
|
+
default: true,
|
|
40
|
+
},
|
|
41
|
+
// File preview width in px.
|
|
42
|
+
previewWidth: {
|
|
43
|
+
default: 512,
|
|
28
44
|
},
|
|
29
45
|
} satisfies PropSchema;
|
|
30
46
|
|
|
31
|
-
|
|
32
|
-
const textAlignmentToAlignItems = (
|
|
33
|
-
textAlignment: "left" | "center" | "right" | "justify"
|
|
34
|
-
): "flex-start" | "center" | "flex-end" => {
|
|
35
|
-
switch (textAlignment) {
|
|
36
|
-
case "left":
|
|
37
|
-
return "flex-start";
|
|
38
|
-
case "center":
|
|
39
|
-
return "center";
|
|
40
|
-
case "right":
|
|
41
|
-
return "flex-end";
|
|
42
|
-
default:
|
|
43
|
-
return "flex-start";
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
// Min image width in px.
|
|
48
|
-
const minWidth = 64;
|
|
49
|
-
|
|
50
|
-
const blockConfig = {
|
|
47
|
+
export const imageBlockConfig = {
|
|
51
48
|
type: "image" as const,
|
|
52
49
|
propSchema: imagePropSchema,
|
|
53
50
|
content: "none",
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
51
|
+
isFileBlock: true,
|
|
52
|
+
isFileBlockPlaceholder: (block: any) => !block.props.url,
|
|
53
|
+
fileBlockAcceptMimeTypes: ["image/*"],
|
|
54
|
+
} satisfies FileBlockConfig;
|
|
55
|
+
|
|
56
|
+
export const imageRender = (
|
|
57
|
+
block: BlockFromConfig<typeof imageBlockConfig, any, any>,
|
|
58
|
+
editor: BlockNoteEditor<any, any, any>
|
|
59
59
|
) => {
|
|
60
|
-
// Wrapper element to set the image alignment, contains both image/image
|
|
61
|
-
// upload dashboard and caption.
|
|
62
60
|
const wrapper = document.createElement("div");
|
|
63
|
-
wrapper.className = "bn-
|
|
64
|
-
wrapper.style.alignItems = textAlignmentToAlignItems(
|
|
65
|
-
block.props.textAlignment
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
// Button element that acts as a placeholder for images with no src.
|
|
69
|
-
const addImageButton = document.createElement("div");
|
|
70
|
-
addImageButton.className = "bn-add-image-button";
|
|
71
|
-
|
|
72
|
-
// Icon for the add image button.
|
|
73
|
-
const addImageButtonIcon = document.createElement("div");
|
|
74
|
-
addImageButtonIcon.className = "bn-add-image-button-icon";
|
|
75
|
-
|
|
76
|
-
// Text for the add image button.
|
|
77
|
-
const addImageButtonText = document.createElement("p");
|
|
78
|
-
addImageButtonText.className = "bn-add-image-button-text";
|
|
79
|
-
addImageButtonText.innerText = editor.dictionary.image.add_button;
|
|
80
|
-
|
|
81
|
-
// Wrapper element for the image, resize handles and caption.
|
|
82
|
-
const imageAndCaptionWrapper = document.createElement("div");
|
|
83
|
-
imageAndCaptionWrapper.className = "bn-image-and-caption-wrapper";
|
|
84
|
-
|
|
85
|
-
// Wrapper element for the image and resize handles.
|
|
86
|
-
const imageWrapper = document.createElement("div");
|
|
87
|
-
imageWrapper.className = "bn-image-wrapper";
|
|
88
|
-
|
|
89
|
-
// Image element.
|
|
90
|
-
const image = document.createElement("img");
|
|
91
|
-
image.className = "bn-image";
|
|
92
|
-
image.src = block.props.url;
|
|
93
|
-
image.alt = "placeholder";
|
|
94
|
-
image.contentEditable = "false";
|
|
95
|
-
image.draggable = false;
|
|
96
|
-
image.style.width = `${Math.min(
|
|
97
|
-
block.props.width,
|
|
98
|
-
editor.domElement.firstElementChild!.clientWidth
|
|
99
|
-
)}px`;
|
|
100
|
-
|
|
101
|
-
// Resize handle elements.
|
|
102
|
-
const leftResizeHandle = document.createElement("div");
|
|
103
|
-
leftResizeHandle.className = "bn-image-resize-handle";
|
|
104
|
-
leftResizeHandle.style.left = "4px";
|
|
105
|
-
const rightResizeHandle = document.createElement("div");
|
|
106
|
-
rightResizeHandle.className = "bn-image-resize-handle";
|
|
107
|
-
rightResizeHandle.style.right = "4px";
|
|
108
|
-
|
|
109
|
-
// Caption element.
|
|
110
|
-
const caption = document.createElement("p");
|
|
111
|
-
caption.className = "bn-image-caption";
|
|
112
|
-
caption.innerText = block.props.caption;
|
|
113
|
-
caption.style.padding = block.props.caption ? "4px" : "";
|
|
61
|
+
wrapper.className = "bn-file-block-content-wrapper";
|
|
114
62
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
addImageButton.style.outline = "4px solid rgb(100, 160, 255)";
|
|
127
|
-
imageAndCaptionWrapper.style.outline = "4px solid rgb(100, 160, 255)";
|
|
128
|
-
} else {
|
|
129
|
-
addImageButton.style.outline = "";
|
|
130
|
-
imageAndCaptionWrapper.style.outline = "";
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
editor.onEditorContentChange(handleEditorUpdate);
|
|
134
|
-
editor.onEditorSelectionChange(handleEditorUpdate);
|
|
135
|
-
|
|
136
|
-
// Temporary parameters set when the user begins resizing the image, used to
|
|
137
|
-
// calculate the new width of the image.
|
|
138
|
-
let resizeParams:
|
|
139
|
-
| {
|
|
140
|
-
handleUsed: "left" | "right";
|
|
141
|
-
initialWidth: number;
|
|
142
|
-
initialClientX: number;
|
|
143
|
-
}
|
|
144
|
-
| undefined;
|
|
145
|
-
|
|
146
|
-
// Updates the image width with an updated width depending on the cursor X
|
|
147
|
-
// offset from when the resize began, and which resize handle is being used.
|
|
148
|
-
const windowMouseMoveHandler = (event: MouseEvent) => {
|
|
149
|
-
if (!resizeParams) {
|
|
150
|
-
if (
|
|
151
|
-
!editor.isEditable &&
|
|
152
|
-
imageWrapper.contains(leftResizeHandle) &&
|
|
153
|
-
imageWrapper.contains(rightResizeHandle)
|
|
154
|
-
) {
|
|
155
|
-
imageWrapper.removeChild(leftResizeHandle);
|
|
156
|
-
imageWrapper.removeChild(rightResizeHandle);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
let newWidth: number;
|
|
163
|
-
|
|
164
|
-
if (textAlignmentToAlignItems(block.props.textAlignment) === "center") {
|
|
165
|
-
if (resizeParams.handleUsed === "left") {
|
|
166
|
-
newWidth =
|
|
167
|
-
resizeParams.initialWidth +
|
|
168
|
-
(resizeParams.initialClientX - event.clientX) * 2;
|
|
169
|
-
} else {
|
|
170
|
-
newWidth =
|
|
171
|
-
resizeParams.initialWidth +
|
|
172
|
-
(event.clientX - resizeParams.initialClientX) * 2;
|
|
173
|
-
}
|
|
174
|
-
} else {
|
|
175
|
-
if (resizeParams.handleUsed === "left") {
|
|
176
|
-
newWidth =
|
|
177
|
-
resizeParams.initialWidth +
|
|
178
|
-
resizeParams.initialClientX -
|
|
179
|
-
event.clientX;
|
|
180
|
-
} else {
|
|
181
|
-
newWidth =
|
|
182
|
-
resizeParams.initialWidth +
|
|
183
|
-
event.clientX -
|
|
184
|
-
resizeParams.initialClientX;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Ensures the image is not wider than the editor and not smaller than a
|
|
189
|
-
// predetermined minimum width.
|
|
190
|
-
if (newWidth < minWidth) {
|
|
191
|
-
image.style.width = `${minWidth}px`;
|
|
192
|
-
} else if (newWidth > editor.domElement.firstElementChild!.clientWidth) {
|
|
193
|
-
image.style.width = `${
|
|
194
|
-
editor.domElement.firstElementChild!.clientWidth
|
|
195
|
-
}px`;
|
|
196
|
-
} else {
|
|
197
|
-
image.style.width = `${newWidth}px`;
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
|
-
// Stops mouse movements from resizing the image and updates the block's
|
|
201
|
-
// `width` prop to the new value.
|
|
202
|
-
const windowMouseUpHandler = (event: MouseEvent) => {
|
|
203
|
-
// Hides the drag handles if the cursor is no longer over the image.
|
|
204
|
-
if (
|
|
205
|
-
(!event.target ||
|
|
206
|
-
!imageWrapper.contains(event.target as Node) ||
|
|
207
|
-
!editor.isEditable) &&
|
|
208
|
-
imageWrapper.contains(leftResizeHandle) &&
|
|
209
|
-
imageWrapper.contains(rightResizeHandle)
|
|
210
|
-
) {
|
|
211
|
-
imageWrapper.removeChild(leftResizeHandle);
|
|
212
|
-
imageWrapper.removeChild(rightResizeHandle);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
if (!resizeParams) {
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
resizeParams = undefined;
|
|
63
|
+
if (block.props.url === "") {
|
|
64
|
+
const fileBlockImageIcon = document.createElement("div");
|
|
65
|
+
fileBlockImageIcon.innerHTML =
|
|
66
|
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M5 11.1005L7 9.1005L12.5 14.6005L16 11.1005L19 14.1005V5H5V11.1005ZM4 3H20C20.5523 3 21 3.44772 21 4V20C21 20.5523 20.5523 21 20 21H4C3.44772 21 3 20.5523 3 20V4C3 3.44772 3.44772 3 4 3ZM15.5 10C14.6716 10 14 9.32843 14 8.5C14 7.67157 14.6716 7 15.5 7C16.3284 7 17 7.67157 17 8.5C17 9.32843 16.3284 10 15.5 10Z"></path></svg>';
|
|
67
|
+
const addImageButton = createAddFileButton(
|
|
68
|
+
block,
|
|
69
|
+
editor,
|
|
70
|
+
editor.dictionary.file_blocks.image.add_button_text,
|
|
71
|
+
fileBlockImageIcon.firstElementChild as HTMLElement
|
|
72
|
+
);
|
|
73
|
+
wrapper.appendChild(addImageButton.dom);
|
|
220
74
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
width: parseFloat(image.style.width.slice(0, -2)) as any,
|
|
75
|
+
return {
|
|
76
|
+
dom: wrapper,
|
|
77
|
+
destroy: () => {
|
|
78
|
+
addImageButton?.destroy?.();
|
|
226
79
|
},
|
|
227
|
-
}
|
|
228
|
-
}
|
|
80
|
+
};
|
|
81
|
+
} else if (!block.props.showPreview) {
|
|
82
|
+
const file = createDefaultFilePreview(block).dom;
|
|
83
|
+
const element = createFileAndCaptionWrapper(block, file);
|
|
229
84
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
85
|
+
return {
|
|
86
|
+
dom: element.dom,
|
|
87
|
+
};
|
|
88
|
+
} else {
|
|
89
|
+
const image = document.createElement("img");
|
|
90
|
+
image.className = "bn-visual-media";
|
|
91
|
+
image.src = block.props.url;
|
|
92
|
+
image.alt = block.props.name || block.props.caption || "BlockNote image";
|
|
93
|
+
image.contentEditable = "false";
|
|
94
|
+
image.draggable = false;
|
|
95
|
+
image.width = Math.min(
|
|
96
|
+
block.props.previewWidth,
|
|
97
|
+
editor.domElement.firstElementChild!.clientWidth
|
|
240
98
|
);
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
// Shows the resize handles when hovering over the image with the cursor.
|
|
244
|
-
const imageMouseEnterHandler = () => {
|
|
245
|
-
if (editor.isEditable) {
|
|
246
|
-
imageWrapper.appendChild(leftResizeHandle);
|
|
247
|
-
imageWrapper.appendChild(rightResizeHandle);
|
|
248
|
-
}
|
|
249
|
-
};
|
|
250
|
-
// Hides the resize handles when the cursor leaves the image, unless the
|
|
251
|
-
// cursor moves to one of the resize handles.
|
|
252
|
-
const imageMouseLeaveHandler = (event: MouseEvent) => {
|
|
253
|
-
if (
|
|
254
|
-
event.relatedTarget === leftResizeHandle ||
|
|
255
|
-
event.relatedTarget === rightResizeHandle
|
|
256
|
-
) {
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
99
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
100
|
+
const file = createResizeHandlesWrapper(
|
|
101
|
+
block,
|
|
102
|
+
editor,
|
|
103
|
+
image,
|
|
104
|
+
() => image.width,
|
|
105
|
+
(width) => (image.width = width)
|
|
106
|
+
);
|
|
263
107
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
imageWrapper.contains(leftResizeHandle) &&
|
|
267
|
-
imageWrapper.contains(rightResizeHandle)
|
|
268
|
-
) {
|
|
269
|
-
imageWrapper.removeChild(leftResizeHandle);
|
|
270
|
-
imageWrapper.removeChild(rightResizeHandle);
|
|
271
|
-
}
|
|
272
|
-
};
|
|
108
|
+
const element = createFileAndCaptionWrapper(block, file.dom);
|
|
109
|
+
wrapper.appendChild(element.dom);
|
|
273
110
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
111
|
+
return {
|
|
112
|
+
dom: wrapper,
|
|
113
|
+
destroy: file.destroy,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
};
|
|
278
117
|
|
|
279
|
-
|
|
280
|
-
|
|
118
|
+
export const imageParse = (
|
|
119
|
+
element: HTMLElement
|
|
120
|
+
): Partial<Props<typeof imageBlockConfig.propSchema>> | undefined => {
|
|
121
|
+
if (element.tagName === "IMG") {
|
|
122
|
+
return parseImageElement(element as HTMLImageElement);
|
|
123
|
+
}
|
|
281
124
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
};
|
|
288
|
-
const rightResizeHandleMouseDownHandler = (event: MouseEvent) => {
|
|
289
|
-
event.preventDefault();
|
|
125
|
+
if (element.tagName === "FIGURE") {
|
|
126
|
+
const parsedFigure = parseFigureElement(element, "img");
|
|
127
|
+
if (!parsedFigure) {
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
290
130
|
|
|
291
|
-
|
|
292
|
-
imageWrapper.appendChild(rightResizeHandle);
|
|
131
|
+
const { targetElement, caption } = parsedFigure;
|
|
293
132
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
initialClientX: event.clientX,
|
|
133
|
+
return {
|
|
134
|
+
...parseImageElement(targetElement as HTMLImageElement),
|
|
135
|
+
caption,
|
|
298
136
|
};
|
|
299
|
-
}
|
|
137
|
+
}
|
|
300
138
|
|
|
301
|
-
|
|
302
|
-
|
|
139
|
+
return undefined;
|
|
140
|
+
};
|
|
303
141
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
142
|
+
export const imageToExternalHTML = (
|
|
143
|
+
block: BlockFromConfig<typeof imageBlockConfig, any, any>
|
|
144
|
+
) => {
|
|
145
|
+
if (!block.props.url) {
|
|
146
|
+
const div = document.createElement("p");
|
|
147
|
+
div.textContent = "Add image";
|
|
307
148
|
|
|
308
|
-
|
|
309
|
-
|
|
149
|
+
return {
|
|
150
|
+
dom: div,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
let image;
|
|
155
|
+
if (block.props.showPreview) {
|
|
156
|
+
image = document.createElement("img");
|
|
157
|
+
image.src = block.props.url;
|
|
158
|
+
image.alt = block.props.name || block.props.caption || "BlockNote image";
|
|
159
|
+
image.width = block.props.previewWidth;
|
|
310
160
|
} else {
|
|
311
|
-
|
|
161
|
+
image = document.createElement("a");
|
|
162
|
+
image.href = block.props.url;
|
|
163
|
+
image.textContent = block.props.name || block.props.url;
|
|
312
164
|
}
|
|
313
165
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
"mousedown",
|
|
322
|
-
leftResizeHandleMouseDownHandler
|
|
323
|
-
);
|
|
324
|
-
rightResizeHandle.addEventListener(
|
|
325
|
-
"mousedown",
|
|
326
|
-
rightResizeHandleMouseDownHandler
|
|
327
|
-
);
|
|
166
|
+
if (block.props.caption) {
|
|
167
|
+
if (block.props.showPreview) {
|
|
168
|
+
return createFigureWithCaption(image, block.props.caption);
|
|
169
|
+
} else {
|
|
170
|
+
return createLinkWithCaption(image, block.props.caption);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
328
173
|
|
|
329
174
|
return {
|
|
330
|
-
dom:
|
|
331
|
-
destroy: () => {
|
|
332
|
-
window.removeEventListener("mousemove", windowMouseMoveHandler);
|
|
333
|
-
window.removeEventListener("mouseup", windowMouseUpHandler);
|
|
334
|
-
addImageButton.removeEventListener(
|
|
335
|
-
"mousedown",
|
|
336
|
-
addImageButtonMouseDownHandler
|
|
337
|
-
);
|
|
338
|
-
addImageButton.removeEventListener("click", addImageButtonClickHandler);
|
|
339
|
-
leftResizeHandle.removeEventListener(
|
|
340
|
-
"mousedown",
|
|
341
|
-
leftResizeHandleMouseDownHandler
|
|
342
|
-
);
|
|
343
|
-
rightResizeHandle.removeEventListener(
|
|
344
|
-
"mousedown",
|
|
345
|
-
rightResizeHandleMouseDownHandler
|
|
346
|
-
);
|
|
347
|
-
},
|
|
175
|
+
dom: image,
|
|
348
176
|
};
|
|
349
177
|
};
|
|
350
178
|
|
|
351
|
-
export const
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
},
|
|
357
|
-
{
|
|
358
|
-
render: renderImage,
|
|
359
|
-
toExternalHTML: (block) => {
|
|
360
|
-
if (block.props.url === "") {
|
|
361
|
-
const div = document.createElement("p");
|
|
362
|
-
div.innerHTML = "Add Image";
|
|
363
|
-
|
|
364
|
-
return {
|
|
365
|
-
dom: div,
|
|
366
|
-
};
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
const figure = document.createElement("figure");
|
|
370
|
-
|
|
371
|
-
const img = document.createElement("img");
|
|
372
|
-
img.src = block.props.url;
|
|
373
|
-
figure.appendChild(img);
|
|
374
|
-
|
|
375
|
-
if (block.props.caption !== "") {
|
|
376
|
-
const figcaption = document.createElement("figcaption");
|
|
377
|
-
figcaption.innerHTML = block.props.caption;
|
|
378
|
-
figure.appendChild(figcaption);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
return {
|
|
382
|
-
dom: figure,
|
|
383
|
-
};
|
|
384
|
-
},
|
|
385
|
-
parse: (element: HTMLElement) => {
|
|
386
|
-
if (element.tagName === "FIGURE") {
|
|
387
|
-
const img = element.querySelector("img");
|
|
388
|
-
const caption = element.querySelector("figcaption");
|
|
389
|
-
return {
|
|
390
|
-
url: img?.getAttribute("src") || "",
|
|
391
|
-
caption:
|
|
392
|
-
caption?.textContent || img?.getAttribute("alt") || undefined,
|
|
393
|
-
};
|
|
394
|
-
} else if (element.tagName === "IMG") {
|
|
395
|
-
return {
|
|
396
|
-
url: element.getAttribute("src") || "",
|
|
397
|
-
caption: element.getAttribute("alt") || undefined,
|
|
398
|
-
};
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
return undefined;
|
|
402
|
-
},
|
|
403
|
-
}
|
|
404
|
-
);
|
|
179
|
+
export const ImageBlock = createBlockSpec(imageBlockConfig, {
|
|
180
|
+
render: imageRender,
|
|
181
|
+
parse: imageParse,
|
|
182
|
+
toExternalHTML: imageToExternalHTML,
|
|
183
|
+
});
|