@blocknote/core 0.2.2 → 0.2.4-alpha.7
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 +1061 -936
- package/dist/blocknote.js.map +1 -1
- package/dist/blocknote.umd.cjs +1 -1
- package/dist/blocknote.umd.cjs.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +22 -29
- package/src/BlockNoteExtensions.ts +11 -10
- package/src/extensions/BackgroundColor/BackgroundColorExtension.ts +61 -0
- package/src/extensions/BackgroundColor/BackgroundColorMark.ts +62 -0
- package/src/extensions/Blocks/PreviousBlockTypePlugin.ts +112 -106
- package/src/extensions/Blocks/apiTypes.ts +48 -0
- package/src/extensions/Blocks/helpers/findBlock.ts +3 -1
- package/src/extensions/Blocks/helpers/getBlockInfoFromPos.ts +1 -1
- package/src/extensions/Blocks/index.ts +10 -8
- package/src/extensions/Blocks/nodes/Block.module.css +122 -35
- package/src/extensions/Blocks/{BlockAttributes.ts → nodes/BlockAttributes.ts} +0 -0
- package/src/extensions/Blocks/nodes/{Block.ts → BlockContainer.ts} +113 -119
- package/src/extensions/Blocks/nodes/{BlockTypes/HeadingBlock/HeadingContent.ts → BlockContent/HeadingBlockContent/HeadingBlockContent.ts} +16 -24
- package/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts +76 -0
- package/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/ListItemKeyboardShortcuts.ts +47 -0
- package/src/extensions/Blocks/nodes/{BlockTypes/ListItemBlock/OrderedListItemIndexPlugin.ts → BlockContent/ListItemBlockContent/NumberedListItemBlockContent/NumberedListIndexingPlugin.ts} +10 -14
- package/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts +95 -0
- package/src/extensions/Blocks/nodes/{BlockTypes/TextBlock/TextContent.ts → BlockContent/ParagraphBlockContent/ParagraphBlockContent.ts} +7 -12
- package/src/extensions/Blocks/nodes/BlockGroup.ts +4 -4
- package/src/extensions/DraggableBlocks/BlockSideMenuFactoryTypes.ts +9 -1
- package/src/extensions/DraggableBlocks/DraggableBlocksPlugin.ts +87 -42
- package/src/extensions/{Blocks → DraggableBlocks}/MultipleNodeSelection.ts +0 -0
- package/src/extensions/FormattingToolbar/FormattingToolbarFactoryTypes.ts +20 -7
- package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +51 -12
- package/src/extensions/HyperlinkToolbar/HyperlinkToolbarFactoryTypes.ts +1 -1
- package/src/extensions/HyperlinkToolbar/HyperlinkToolbarPlugin.ts +3 -1
- package/src/extensions/Placeholder/PlaceholderExtension.ts +1 -1
- package/src/extensions/SlashMenu/SlashMenuExtension.ts +1 -1
- package/src/extensions/SlashMenu/SlashMenuItem.ts +3 -28
- package/src/extensions/SlashMenu/defaultCommands.tsx +36 -55
- package/src/extensions/SlashMenu/index.ts +1 -6
- package/src/extensions/TextAlignment/TextAlignmentExtension.ts +75 -0
- package/src/extensions/TextColor/TextColorExtension.ts +54 -0
- package/src/extensions/TextColor/TextColorMark.ts +62 -0
- package/src/extensions/TrailingNode/TrailingNodeExtension.ts +4 -4
- package/src/extensions/UniqueID/UniqueID.ts +6 -0
- package/src/index.ts +2 -1
- package/src/shared/EditorElement.ts +12 -6
- package/src/shared/plugins/suggestion/SuggestionItem.ts +0 -9
- package/src/shared/plugins/suggestion/SuggestionPlugin.ts +191 -228
- package/src/shared/plugins/suggestion/SuggestionsMenuFactoryTypes.ts +2 -2
- package/types/src/BlockNoteEditor.d.ts +1 -1
- package/types/src/BlockNoteExtensions.d.ts +1 -3
- package/types/src/api/Document.d.ts +5 -0
- package/types/src/extensions/BackgroundColor/BackgroundColorExtension.d.ts +9 -0
- package/types/src/extensions/BackgroundColor/BackgroundColorMark.d.ts +9 -0
- package/types/src/extensions/Blocks/PreviousBlockTypePlugin.d.ts +3 -2
- package/types/src/extensions/Blocks/apiTypes.d.ts +16 -0
- package/types/src/extensions/Blocks/helpers/getBlockInfoFromPos.d.ts +1 -1
- package/types/src/extensions/Blocks/nodes/BlockAttributes.d.ts +2 -0
- package/types/src/extensions/Blocks/nodes/BlockContainer.d.ts +21 -0
- package/types/src/extensions/Blocks/nodes/BlockContent/BlockContentTypes.d.ts +4 -0
- package/types/src/extensions/Blocks/nodes/BlockContent/HeadingBlockContent/HeadingBlockContent.d.ts +2 -0
- package/types/src/extensions/Blocks/nodes/BlockContent/HeadingBlockContent/HeadingBlockContentTypes.d.ts +4 -0
- package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.d.ts +2 -0
- package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContentTypes.d.ts +2 -0
- package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/ListItemKeyboardShortcuts.d.ts +2 -0
- package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/NumberedListItemBlockContent/NumberedListIndexingPlugin.d.ts +2 -0
- package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.d.ts +2 -0
- package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContentTypes.d.ts +2 -0
- package/types/src/extensions/Blocks/nodes/BlockContent/ParagraphBlockContent/ParagraphBlockContent.d.ts +2 -0
- package/types/src/extensions/Blocks/nodes/BlockContent/ParagraphBlockContent/ParagraphBlockContentTypes.d.ts +2 -0
- package/types/src/extensions/DraggableBlocks/BlockSideMenuFactoryTypes.d.ts +9 -5
- package/types/src/extensions/DraggableBlocks/DraggableBlocksExtension.d.ts +1 -1
- package/types/src/extensions/DraggableBlocks/DraggableBlocksPlugin.d.ts +6 -11
- package/types/src/extensions/DraggableBlocks/MultipleNodeSelection.d.ts +24 -0
- package/types/src/extensions/FormattingToolbar/FormattingToolbarFactoryTypes.d.ts +18 -8
- package/types/src/extensions/FormattingToolbar/FormattingToolbarPlugin.d.ts +1 -1
- package/types/src/extensions/HyperlinkToolbar/HyperlinkToolbarFactoryTypes.d.ts +5 -5
- package/types/src/extensions/HyperlinkToolbar/HyperlinkToolbarPlugin.d.ts +2 -2
- package/types/src/extensions/SlashMenu/SlashMenuExtension.d.ts +1 -1
- package/types/src/extensions/SlashMenu/SlashMenuItem.d.ts +2 -19
- package/types/src/extensions/SlashMenu/defaultSlashCommands.d.ts +5 -0
- package/types/src/extensions/SlashMenu/index.d.ts +1 -2
- package/types/src/extensions/TextAlignment/TextAlignmentExtension.d.ts +9 -0
- package/types/src/extensions/TextColor/TextColorExtension.d.ts +9 -0
- package/types/src/extensions/TextColor/TextColorMark.d.ts +9 -0
- package/types/src/index.d.ts +2 -1
- package/types/src/shared/EditorElement.d.ts +6 -2
- package/types/src/shared/plugins/suggestion/SuggestionItem.d.ts +0 -6
- package/types/src/shared/plugins/suggestion/SuggestionPlugin.d.ts +11 -25
- package/types/src/shared/plugins/suggestion/SuggestionsMenuFactoryTypes.d.ts +6 -6
- package/src/extensions/Blocks/nodes/BlockTypes/ListItemBlock/ListItemContent.ts +0 -177
- package/src/extensions/Paragraph/FixedParagraph.ts +0 -12
|
@@ -3,36 +3,23 @@ import { Node } from "prosemirror-model";
|
|
|
3
3
|
import { NodeSelection, Plugin, PluginKey, Selection } from "prosemirror-state";
|
|
4
4
|
import * as pv from "prosemirror-view";
|
|
5
5
|
import { EditorView } from "prosemirror-view";
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
6
|
+
import styles from "../../editor.module.css";
|
|
7
|
+
import { getBlockInfoFromPos } from "../Blocks/helpers/getBlockInfoFromPos";
|
|
8
|
+
import { SlashMenuPluginKey } from "../SlashMenu/SlashMenuExtension";
|
|
8
9
|
import {
|
|
9
10
|
BlockSideMenu,
|
|
10
11
|
BlockSideMenuDynamicParams,
|
|
11
12
|
BlockSideMenuFactory,
|
|
12
13
|
BlockSideMenuStaticParams,
|
|
13
14
|
} from "./BlockSideMenuFactoryTypes";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import styles from "../../editor.module.css";
|
|
15
|
+
import { DraggableBlocksOptions } from "./DraggableBlocksExtension";
|
|
16
|
+
import { MultipleNodeSelection } from "./MultipleNodeSelection";
|
|
17
17
|
|
|
18
18
|
const serializeForClipboard = (pv as any).__serializeForClipboard;
|
|
19
19
|
// code based on https://github.com/ueberdosis/tiptap/issues/323#issuecomment-506637799
|
|
20
20
|
|
|
21
|
-
let horizontalAnchor: number;
|
|
22
21
|
let dragImageElement: Element | undefined;
|
|
23
22
|
|
|
24
|
-
function getHorizontalAnchor() {
|
|
25
|
-
if (!horizontalAnchor) {
|
|
26
|
-
const firstBlockGroup = document.querySelector(
|
|
27
|
-
".ProseMirror > [class*='blockGroup']"
|
|
28
|
-
) as HTMLElement | undefined; // first block group node
|
|
29
|
-
if (firstBlockGroup) {
|
|
30
|
-
horizontalAnchor = absoluteRect(firstBlockGroup).left;
|
|
31
|
-
} // Anchor to the left of the first block group
|
|
32
|
-
}
|
|
33
|
-
return horizontalAnchor;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
23
|
export function createRect(rect: DOMRect) {
|
|
37
24
|
let newRect = {
|
|
38
25
|
left: rect.left + document.body.scrollLeft,
|
|
@@ -47,10 +34,6 @@ export function createRect(rect: DOMRect) {
|
|
|
47
34
|
return newRect;
|
|
48
35
|
}
|
|
49
36
|
|
|
50
|
-
export function absoluteRect(element: HTMLElement) {
|
|
51
|
-
return createRect(element.getBoundingClientRect());
|
|
52
|
-
}
|
|
53
|
-
|
|
54
37
|
function getDraggableBlockFromCoords(
|
|
55
38
|
coords: { left: number; top: number },
|
|
56
39
|
view: EditorView
|
|
@@ -184,8 +167,10 @@ function dragStart(e: DragEvent, view: EditorView) {
|
|
|
184
167
|
return;
|
|
185
168
|
}
|
|
186
169
|
|
|
170
|
+
const editorBoundingBox = view.dom.getBoundingClientRect();
|
|
171
|
+
|
|
187
172
|
let coords = {
|
|
188
|
-
left:
|
|
173
|
+
left: editorBoundingBox.left + editorBoundingBox.width / 2, // take middle of editor
|
|
189
174
|
top: e.clientY,
|
|
190
175
|
};
|
|
191
176
|
|
|
@@ -238,9 +223,11 @@ export class BlockMenuView {
|
|
|
238
223
|
// When false, the drag handle with be just to the left of the element
|
|
239
224
|
horizontalPosAnchoredAtRoot: boolean;
|
|
240
225
|
|
|
226
|
+
horizontalPosAnchor: number;
|
|
227
|
+
|
|
241
228
|
blockMenu: BlockSideMenu;
|
|
242
229
|
|
|
243
|
-
|
|
230
|
+
hoveredBlockContent: HTMLElement | undefined;
|
|
244
231
|
|
|
245
232
|
menuOpen = false;
|
|
246
233
|
menuFrozen = false;
|
|
@@ -252,6 +239,9 @@ export class BlockMenuView {
|
|
|
252
239
|
}: BlockMenuViewProps) {
|
|
253
240
|
this.editor = editor;
|
|
254
241
|
this.horizontalPosAnchoredAtRoot = horizontalPosAnchoredAtRoot;
|
|
242
|
+
this.horizontalPosAnchor = (
|
|
243
|
+
editor.view.dom.firstChild! as HTMLElement
|
|
244
|
+
).getBoundingClientRect().x;
|
|
255
245
|
|
|
256
246
|
this.blockMenu = blockMenuFactory(this.getStaticParams());
|
|
257
247
|
|
|
@@ -263,9 +253,17 @@ export class BlockMenuView {
|
|
|
263
253
|
return;
|
|
264
254
|
}
|
|
265
255
|
|
|
256
|
+
// Editor itself may have padding or other styling which affects size/position, so we get the boundingRect of
|
|
257
|
+
// the first child (i.e. the blockGroup that wraps all blocks in the editor) for a more accurate bounding box.
|
|
258
|
+
const editorBoundingBox = (
|
|
259
|
+
this.editor.view.dom.firstChild! as HTMLElement
|
|
260
|
+
).getBoundingClientRect();
|
|
261
|
+
|
|
262
|
+
this.horizontalPosAnchor = editorBoundingBox.x;
|
|
263
|
+
|
|
266
264
|
// Gets block at mouse cursor's vertical position.
|
|
267
265
|
const coords = {
|
|
268
|
-
left:
|
|
266
|
+
left: editorBoundingBox.left + editorBoundingBox.width / 2, // take middle of editor
|
|
269
267
|
top: event.clientY,
|
|
270
268
|
};
|
|
271
269
|
const block = getDraggableBlockFromCoords(coords, this.editor.view);
|
|
@@ -283,15 +281,15 @@ export class BlockMenuView {
|
|
|
283
281
|
// Doesn't update if the menu is already open and the mouse cursor is still hovering the same block.
|
|
284
282
|
if (
|
|
285
283
|
this.menuOpen &&
|
|
286
|
-
this.
|
|
287
|
-
this.
|
|
284
|
+
this.hoveredBlockContent?.hasAttribute("data-id") &&
|
|
285
|
+
this.hoveredBlockContent?.getAttribute("data-id") === block.id
|
|
288
286
|
) {
|
|
289
287
|
return;
|
|
290
288
|
}
|
|
291
289
|
|
|
292
290
|
// Gets the block's content node, which lets to ignore child blocks when determining the block menu's position.
|
|
293
291
|
const blockContent = block.node.firstChild as HTMLElement;
|
|
294
|
-
this.
|
|
292
|
+
this.hoveredBlockContent = blockContent;
|
|
295
293
|
|
|
296
294
|
if (!blockContent) {
|
|
297
295
|
return;
|
|
@@ -352,11 +350,12 @@ export class BlockMenuView {
|
|
|
352
350
|
this.menuFrozen = true;
|
|
353
351
|
this.blockMenu.hide();
|
|
354
352
|
|
|
355
|
-
const
|
|
353
|
+
const blockContentBoundingBox =
|
|
354
|
+
this.hoveredBlockContent!.getBoundingClientRect();
|
|
356
355
|
|
|
357
356
|
const pos = this.editor.view.posAtCoords({
|
|
358
|
-
left:
|
|
359
|
-
top:
|
|
357
|
+
left: blockContentBoundingBox.left + blockContentBoundingBox.width / 2,
|
|
358
|
+
top: blockContentBoundingBox.top + blockContentBoundingBox.height / 2,
|
|
360
359
|
});
|
|
361
360
|
if (!pos) {
|
|
362
361
|
return;
|
|
@@ -377,9 +376,11 @@ export class BlockMenuView {
|
|
|
377
376
|
this.editor
|
|
378
377
|
.chain()
|
|
379
378
|
.BNCreateBlock(newBlockInsertionPos)
|
|
380
|
-
.
|
|
379
|
+
.BNUpdateBlock(newBlockContentPos, { type: "paragraph", props: {} })
|
|
381
380
|
.setTextSelection(newBlockContentPos)
|
|
382
381
|
.run();
|
|
382
|
+
} else {
|
|
383
|
+
this.editor.commands.setTextSelection(endPos);
|
|
383
384
|
}
|
|
384
385
|
|
|
385
386
|
// Focuses and activates the suggestion menu.
|
|
@@ -397,11 +398,12 @@ export class BlockMenuView {
|
|
|
397
398
|
this.menuOpen = false;
|
|
398
399
|
this.blockMenu.hide();
|
|
399
400
|
|
|
400
|
-
const
|
|
401
|
+
const blockContentBoundingBox =
|
|
402
|
+
this.hoveredBlockContent!.getBoundingClientRect();
|
|
401
403
|
|
|
402
404
|
const pos = this.editor.view.posAtCoords({
|
|
403
|
-
left:
|
|
404
|
-
top:
|
|
405
|
+
left: blockContentBoundingBox.left + blockContentBoundingBox.width / 2,
|
|
406
|
+
top: blockContentBoundingBox.top + blockContentBoundingBox.height / 2,
|
|
405
407
|
});
|
|
406
408
|
if (!pos) {
|
|
407
409
|
return;
|
|
@@ -410,6 +412,42 @@ export class BlockMenuView {
|
|
|
410
412
|
this.editor.commands.BNDeleteBlock(pos.pos);
|
|
411
413
|
}
|
|
412
414
|
|
|
415
|
+
setBlockBackgroundColor(color: string) {
|
|
416
|
+
this.menuOpen = false;
|
|
417
|
+
this.blockMenu.hide();
|
|
418
|
+
|
|
419
|
+
const blockContentBoundingBox =
|
|
420
|
+
this.hoveredBlockContent!.getBoundingClientRect();
|
|
421
|
+
|
|
422
|
+
const pos = this.editor.view.posAtCoords({
|
|
423
|
+
left: blockContentBoundingBox.left + blockContentBoundingBox.width / 2,
|
|
424
|
+
top: blockContentBoundingBox.top + blockContentBoundingBox.height / 2,
|
|
425
|
+
});
|
|
426
|
+
if (!pos) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
this.editor.commands.setBlockBackgroundColor(pos.pos, color);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
setBlockTextColor(color: string) {
|
|
434
|
+
this.menuOpen = false;
|
|
435
|
+
this.blockMenu.hide();
|
|
436
|
+
|
|
437
|
+
const blockContentBoundingBox =
|
|
438
|
+
this.hoveredBlockContent!.getBoundingClientRect();
|
|
439
|
+
|
|
440
|
+
const pos = this.editor.view.posAtCoords({
|
|
441
|
+
left: blockContentBoundingBox.left + blockContentBoundingBox.width / 2,
|
|
442
|
+
top: blockContentBoundingBox.top + blockContentBoundingBox.height / 2,
|
|
443
|
+
});
|
|
444
|
+
if (!pos) {
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
this.editor.commands.setBlockTextColor(pos.pos, color);
|
|
449
|
+
}
|
|
450
|
+
|
|
413
451
|
getStaticParams(): BlockSideMenuStaticParams {
|
|
414
452
|
return {
|
|
415
453
|
addBlock: () => this.addBlock(),
|
|
@@ -422,20 +460,27 @@ export class BlockMenuView {
|
|
|
422
460
|
unfreezeMenu: () => {
|
|
423
461
|
this.menuFrozen = false;
|
|
424
462
|
},
|
|
463
|
+
setBlockBackgroundColor: (color: string) =>
|
|
464
|
+
this.setBlockBackgroundColor(color),
|
|
465
|
+
setBlockTextColor: (color: string) => this.setBlockTextColor(color),
|
|
425
466
|
};
|
|
426
467
|
}
|
|
427
468
|
|
|
428
469
|
getDynamicParams(): BlockSideMenuDynamicParams {
|
|
429
|
-
const
|
|
470
|
+
const blockContentBoundingBox =
|
|
471
|
+
this.hoveredBlockContent!.getBoundingClientRect();
|
|
430
472
|
|
|
431
473
|
return {
|
|
432
|
-
|
|
474
|
+
blockBackgroundColor:
|
|
475
|
+
this.editor.getAttributes("blockContainer").backgroundColor,
|
|
476
|
+
blockTextColor: this.editor.getAttributes("blockContainer").textColor,
|
|
477
|
+
referenceRect: new DOMRect(
|
|
433
478
|
this.horizontalPosAnchoredAtRoot
|
|
434
|
-
?
|
|
435
|
-
:
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
479
|
+
? this.horizontalPosAnchor
|
|
480
|
+
: blockContentBoundingBox.x,
|
|
481
|
+
blockContentBoundingBox.y,
|
|
482
|
+
blockContentBoundingBox.width,
|
|
483
|
+
blockContentBoundingBox.height
|
|
439
484
|
),
|
|
440
485
|
};
|
|
441
486
|
}
|
|
File without changes
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EditorElement, ElementFactory } from "../../shared/EditorElement";
|
|
2
|
-
import {
|
|
2
|
+
import { Block, BlockUpdate } from "../Blocks/apiTypes";
|
|
3
3
|
|
|
4
4
|
export type FormattingToolbarStaticParams = {
|
|
5
5
|
toggleBold: () => void;
|
|
@@ -8,7 +8,16 @@ export type FormattingToolbarStaticParams = {
|
|
|
8
8
|
toggleStrike: () => void;
|
|
9
9
|
setHyperlink: (url: string, text?: string) => void;
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
setTextColor: (color: string) => void;
|
|
12
|
+
setBackgroundColor: (color: string) => void;
|
|
13
|
+
setTextAlignment: (
|
|
14
|
+
textAlignment: "left" | "center" | "right" | "justify"
|
|
15
|
+
) => void;
|
|
16
|
+
|
|
17
|
+
increaseBlockIndent: () => void;
|
|
18
|
+
decreaseBlockIndent: () => void;
|
|
19
|
+
|
|
20
|
+
updateBlock: (blockUpdate: BlockUpdate) => void;
|
|
12
21
|
};
|
|
13
22
|
|
|
14
23
|
export type FormattingToolbarDynamicParams = {
|
|
@@ -20,12 +29,16 @@ export type FormattingToolbarDynamicParams = {
|
|
|
20
29
|
activeHyperlinkUrl: string;
|
|
21
30
|
activeHyperlinkText: string;
|
|
22
31
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
32
|
+
textColor: string;
|
|
33
|
+
backgroundColor: string;
|
|
34
|
+
textAlignment: "left" | "center" | "right" | "justify";
|
|
35
|
+
|
|
36
|
+
canIncreaseBlockIndent: boolean;
|
|
37
|
+
canDecreaseBlockIndent: boolean;
|
|
38
|
+
|
|
39
|
+
block: Block;
|
|
27
40
|
|
|
28
|
-
|
|
41
|
+
referenceRect: DOMRect;
|
|
29
42
|
};
|
|
30
43
|
|
|
31
44
|
export type FormattingToolbar = EditorElement<FormattingToolbarDynamicParams>;
|
|
@@ -6,13 +6,14 @@ import {
|
|
|
6
6
|
} from "@tiptap/core";
|
|
7
7
|
import { EditorState, Plugin, PluginKey } from "prosemirror-state";
|
|
8
8
|
import { EditorView } from "prosemirror-view";
|
|
9
|
+
import { Block, BlockUpdate } from "../Blocks/apiTypes";
|
|
10
|
+
import { getBlockInfoFromPos } from "../Blocks/helpers/getBlockInfoFromPos";
|
|
9
11
|
import {
|
|
10
12
|
FormattingToolbar,
|
|
11
13
|
FormattingToolbarDynamicParams,
|
|
12
14
|
FormattingToolbarFactory,
|
|
13
15
|
FormattingToolbarStaticParams,
|
|
14
16
|
} from "./FormattingToolbarFactoryTypes";
|
|
15
|
-
import { BlockContentType } from "../Blocks/nodes/Block";
|
|
16
17
|
|
|
17
18
|
// Same as TipTap bubblemenu plugin, but with these changes:
|
|
18
19
|
// https://github.com/ueberdosis/tiptap/pull/2596/files
|
|
@@ -265,35 +266,73 @@ export class FormattingToolbarView {
|
|
|
265
266
|
);
|
|
266
267
|
this.editor.view.focus();
|
|
267
268
|
},
|
|
268
|
-
|
|
269
|
+
setTextColor: (color: string) => {
|
|
269
270
|
this.editor.view.focus();
|
|
270
|
-
this.editor.commands.
|
|
271
|
+
this.editor.commands.setTextColor(color);
|
|
272
|
+
},
|
|
273
|
+
setBackgroundColor: (color: string) => {
|
|
274
|
+
this.editor.view.focus();
|
|
275
|
+
this.editor.commands.setBackgroundColor(color);
|
|
276
|
+
},
|
|
277
|
+
setTextAlignment: (
|
|
278
|
+
textAlignment: "left" | "center" | "right" | "justify"
|
|
279
|
+
) => {
|
|
280
|
+
this.editor.view.focus();
|
|
281
|
+
this.editor.commands.setTextAlignment(textAlignment);
|
|
282
|
+
},
|
|
283
|
+
increaseBlockIndent: () => {
|
|
284
|
+
this.editor.view.focus();
|
|
285
|
+
this.editor.commands.sinkListItem("blockContainer");
|
|
286
|
+
},
|
|
287
|
+
decreaseBlockIndent: () => {
|
|
288
|
+
this.editor.view.focus();
|
|
289
|
+
this.editor.commands.liftListItem("blockContainer");
|
|
290
|
+
},
|
|
291
|
+
updateBlock: (blockUpdate: BlockUpdate) => {
|
|
292
|
+
this.editor.view.focus();
|
|
293
|
+
this.editor.commands.BNUpdateBlock(
|
|
271
294
|
this.editor.state.selection.from,
|
|
272
|
-
|
|
295
|
+
blockUpdate
|
|
273
296
|
);
|
|
274
297
|
},
|
|
275
298
|
};
|
|
276
299
|
}
|
|
277
300
|
|
|
278
301
|
getDynamicParams(): FormattingToolbarDynamicParams {
|
|
302
|
+
const blockInfo = getBlockInfoFromPos(
|
|
303
|
+
this.editor.state.doc,
|
|
304
|
+
this.editor.state.selection.from
|
|
305
|
+
)!;
|
|
306
|
+
|
|
279
307
|
return {
|
|
280
308
|
boldIsActive: this.editor.isActive("bold"),
|
|
281
309
|
italicIsActive: this.editor.isActive("italic"),
|
|
282
310
|
underlineIsActive: this.editor.isActive("underline"),
|
|
283
311
|
strikeIsActive: this.editor.isActive("strike"),
|
|
284
312
|
hyperlinkIsActive: this.editor.isActive("link"),
|
|
285
|
-
activeHyperlinkUrl: this.editor.getAttributes("link").href
|
|
286
|
-
? this.editor.getAttributes("link").href
|
|
287
|
-
: "",
|
|
313
|
+
activeHyperlinkUrl: this.editor.getAttributes("link").href || "",
|
|
288
314
|
activeHyperlinkText: this.editor.state.doc.textBetween(
|
|
289
315
|
this.editor.state.selection.from,
|
|
290
316
|
this.editor.state.selection.to
|
|
291
317
|
),
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
318
|
+
textColor: this.editor.getAttributes("textColor").color || "default",
|
|
319
|
+
backgroundColor:
|
|
320
|
+
this.editor.getAttributes("backgroundColor").color || "default",
|
|
321
|
+
textAlignment:
|
|
322
|
+
this.editor.getAttributes(blockInfo.contentType).textAlignment ||
|
|
323
|
+
"left",
|
|
324
|
+
canIncreaseBlockIndent:
|
|
325
|
+
this.editor.state.doc
|
|
326
|
+
.resolve(blockInfo.startPos)
|
|
327
|
+
.index(blockInfo.depth - 1) > 0,
|
|
328
|
+
canDecreaseBlockIndent: blockInfo.depth > 2,
|
|
329
|
+
// Needs type cast as there is no way to create a type that dynamically updates based on which extensions are
|
|
330
|
+
// loaded by the editor.
|
|
331
|
+
block: {
|
|
332
|
+
type: blockInfo.contentType.name,
|
|
333
|
+
props: blockInfo.contentNode.attrs,
|
|
334
|
+
} as Block,
|
|
335
|
+
referenceRect: this.getSelectionBoundingBox(),
|
|
297
336
|
};
|
|
298
337
|
}
|
|
299
338
|
}
|
|
@@ -166,6 +166,8 @@ class HyperlinkToolbarView {
|
|
|
166
166
|
|
|
167
167
|
// Updates menu.
|
|
168
168
|
this.hyperlinkToolbar.render(this.getDynamicParams(), false);
|
|
169
|
+
|
|
170
|
+
return;
|
|
169
171
|
}
|
|
170
172
|
|
|
171
173
|
// Hides menu.
|
|
@@ -227,7 +229,7 @@ class HyperlinkToolbarView {
|
|
|
227
229
|
this.hyperlinkMarkRange!.from,
|
|
228
230
|
this.hyperlinkMarkRange!.to
|
|
229
231
|
),
|
|
230
|
-
|
|
232
|
+
referenceRect: posToDOMRect(
|
|
231
233
|
this.editor.view,
|
|
232
234
|
this.hyperlinkMarkRange!.from,
|
|
233
235
|
this.hyperlinkMarkRange!.to
|
|
@@ -81,7 +81,7 @@ export const Placeholder = Extension.create<PlaceholderOptions>({
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
// If slash menu is of drag type and active, show the filter placeholder
|
|
84
|
-
if (menuState?.
|
|
84
|
+
if (menuState?.triggerCharacter === "" && menuState?.active) {
|
|
85
85
|
classes.push(this.options.isFilterClass);
|
|
86
86
|
}
|
|
87
87
|
// using widget, didn't work (caret position bug)
|
|
@@ -31,7 +31,7 @@ export const SlashMenuExtension = Extension.create<SlashMenuOptions>({
|
|
|
31
31
|
createSuggestionPlugin<SlashMenuItem>({
|
|
32
32
|
pluginKey: SlashMenuPluginKey,
|
|
33
33
|
editor: this.editor,
|
|
34
|
-
|
|
34
|
+
defaultTriggerCharacter: "/",
|
|
35
35
|
suggestionsMenuFactory: this.options.slashMenuFactory!,
|
|
36
36
|
items: (query) => {
|
|
37
37
|
const commands = [];
|
|
@@ -1,49 +1,24 @@
|
|
|
1
1
|
import { Editor, Range } from "@tiptap/core";
|
|
2
2
|
import { SuggestionItem } from "../../shared/plugins/suggestion/SuggestionItem";
|
|
3
3
|
|
|
4
|
-
export type SlashMenuCallback = (editor: Editor, range: Range) => boolean;
|
|
5
|
-
|
|
6
|
-
export enum SlashMenuGroups {
|
|
7
|
-
HEADINGS = "Headings",
|
|
8
|
-
BASIC_BLOCKS = "Basic Blocks",
|
|
9
|
-
CODE = "Code Blocks",
|
|
10
|
-
|
|
11
|
-
// Just some examples, that are not currently in use
|
|
12
|
-
INLINE = "Inline",
|
|
13
|
-
EMBED = "Embed",
|
|
14
|
-
PLUGIN = "Plugin",
|
|
15
|
-
}
|
|
16
|
-
|
|
17
4
|
/**
|
|
18
5
|
* A class that defines a slash command (/<command>).
|
|
19
6
|
*
|
|
20
7
|
* Not to be confused with ProseMirror commands nor TipTap commands.
|
|
21
8
|
*/
|
|
22
9
|
export class SlashMenuItem implements SuggestionItem {
|
|
23
|
-
groupName: string;
|
|
24
|
-
// other parameters initialized in the constructor
|
|
25
|
-
|
|
26
10
|
/**
|
|
27
11
|
* Constructs a new slash-command.
|
|
28
12
|
*
|
|
29
13
|
* @param name The name of the command
|
|
30
|
-
* @param group Used to organize the menu
|
|
31
14
|
* @param execute The callback for creating a new node
|
|
32
15
|
* @param aliases Aliases for this command
|
|
33
|
-
* @param icon To be shown next to the name in the menu
|
|
34
|
-
* @param hint Short description of command
|
|
35
|
-
* @param shortcut Info about keyboard shortcut that would activate this command
|
|
36
16
|
*/
|
|
37
17
|
constructor(
|
|
38
18
|
public readonly name: string,
|
|
39
|
-
public readonly
|
|
40
|
-
public readonly
|
|
41
|
-
|
|
42
|
-
public readonly hint?: string,
|
|
43
|
-
public readonly shortcut?: string
|
|
44
|
-
) {
|
|
45
|
-
this.groupName = group;
|
|
46
|
-
}
|
|
19
|
+
public readonly execute: (editor: Editor, range: Range) => void,
|
|
20
|
+
public readonly aliases: string[] = []
|
|
21
|
+
) {}
|
|
47
22
|
|
|
48
23
|
match(query: string): boolean {
|
|
49
24
|
return (
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { SlashMenuItem } from "./SlashMenuItem";
|
|
2
|
+
import { Editor, Range } from "@tiptap/core";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* An array containing commands for creating all default blocks.
|
|
@@ -8,128 +8,109 @@ const defaultCommands: { [key: string]: SlashMenuItem } = {
|
|
|
8
8
|
// Command for creating a level 1 heading
|
|
9
9
|
heading: new SlashMenuItem(
|
|
10
10
|
"Heading",
|
|
11
|
-
|
|
12
|
-
(editor, range) => {
|
|
11
|
+
(editor: Editor, range: Range) => {
|
|
13
12
|
return editor
|
|
14
13
|
.chain()
|
|
15
14
|
.focus()
|
|
16
15
|
.deleteRange(range)
|
|
17
|
-
.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
.BNCreateOrUpdateBlock(range.from, {
|
|
17
|
+
type: "heading",
|
|
18
|
+
props: {
|
|
19
|
+
level: "1",
|
|
21
20
|
},
|
|
22
21
|
})
|
|
23
22
|
.run();
|
|
24
23
|
},
|
|
25
|
-
["h", "heading1", "h1"]
|
|
26
|
-
"Used for a top-level heading",
|
|
27
|
-
formatKeyboardShortcut("Mod-Alt-1")
|
|
24
|
+
["h", "heading1", "h1"]
|
|
28
25
|
),
|
|
29
26
|
|
|
30
27
|
// Command for creating a level 2 heading
|
|
31
28
|
heading2: new SlashMenuItem(
|
|
32
29
|
"Heading 2",
|
|
33
|
-
|
|
34
|
-
(editor, range) => {
|
|
30
|
+
(editor: Editor, range: Range) => {
|
|
35
31
|
return editor
|
|
36
32
|
.chain()
|
|
37
33
|
.focus()
|
|
38
34
|
.deleteRange(range)
|
|
39
|
-
.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
35
|
+
.BNCreateOrUpdateBlock(range.from, {
|
|
36
|
+
type: "heading",
|
|
37
|
+
props: {
|
|
38
|
+
level: "2",
|
|
43
39
|
},
|
|
44
40
|
})
|
|
45
41
|
.run();
|
|
46
42
|
},
|
|
47
|
-
["h2", "heading2", "subheading"]
|
|
48
|
-
"Used for key sections",
|
|
49
|
-
formatKeyboardShortcut("Mod-Alt-2")
|
|
43
|
+
["h2", "heading2", "subheading"]
|
|
50
44
|
),
|
|
51
45
|
|
|
52
46
|
// Command for creating a level 3 heading
|
|
53
47
|
heading3: new SlashMenuItem(
|
|
54
48
|
"Heading 3",
|
|
55
|
-
|
|
56
|
-
(editor, range) => {
|
|
49
|
+
(editor: Editor, range: Range) => {
|
|
57
50
|
return editor
|
|
58
51
|
.chain()
|
|
59
52
|
.focus()
|
|
60
53
|
.deleteRange(range)
|
|
61
|
-
.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
54
|
+
.BNCreateOrUpdateBlock(range.from, {
|
|
55
|
+
type: "heading",
|
|
56
|
+
props: {
|
|
57
|
+
level: "3",
|
|
65
58
|
},
|
|
66
59
|
})
|
|
67
60
|
.run();
|
|
68
61
|
},
|
|
69
|
-
["h3", "heading3", "subheading"]
|
|
70
|
-
"Used for subsections and group headings",
|
|
71
|
-
formatKeyboardShortcut("Mod-Alt-3")
|
|
62
|
+
["h3", "heading3", "subheading"]
|
|
72
63
|
),
|
|
73
64
|
|
|
74
65
|
// Command for creating an ordered list
|
|
75
66
|
numberedList: new SlashMenuItem(
|
|
76
67
|
"Numbered List",
|
|
77
|
-
|
|
78
|
-
(editor, range) => {
|
|
68
|
+
(editor: Editor, range: Range) => {
|
|
79
69
|
return editor
|
|
80
70
|
.chain()
|
|
81
71
|
.focus()
|
|
82
72
|
.deleteRange(range)
|
|
83
|
-
.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
listItemType: "ordered",
|
|
87
|
-
},
|
|
73
|
+
.BNCreateOrUpdateBlock(range.from, {
|
|
74
|
+
type: "numberedListItem",
|
|
75
|
+
props: {},
|
|
88
76
|
})
|
|
89
77
|
.run();
|
|
90
78
|
},
|
|
91
|
-
["li", "list", "numberedlist", "numbered list"]
|
|
92
|
-
"Used to display a numbered list",
|
|
93
|
-
formatKeyboardShortcut("Mod-Shift-7")
|
|
79
|
+
["li", "list", "numberedlist", "numbered list"]
|
|
94
80
|
),
|
|
95
81
|
|
|
96
82
|
// Command for creating a bullet list
|
|
97
83
|
bulletList: new SlashMenuItem(
|
|
98
84
|
"Bullet List",
|
|
99
|
-
|
|
100
|
-
(editor, range) => {
|
|
85
|
+
(editor: Editor, range: Range) => {
|
|
101
86
|
return editor
|
|
102
87
|
.chain()
|
|
103
88
|
.focus()
|
|
104
89
|
.deleteRange(range)
|
|
105
|
-
.
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
listItemType: "unordered",
|
|
109
|
-
},
|
|
90
|
+
.BNCreateOrUpdateBlock(range.from, {
|
|
91
|
+
type: "bulletListItem",
|
|
92
|
+
props: {},
|
|
110
93
|
})
|
|
111
94
|
.run();
|
|
112
95
|
},
|
|
113
|
-
["ul", "list", "bulletlist", "bullet list"]
|
|
114
|
-
"Used to display an unordered list",
|
|
115
|
-
formatKeyboardShortcut("Mod-Shift-8")
|
|
96
|
+
["ul", "list", "bulletlist", "bullet list"]
|
|
116
97
|
),
|
|
117
98
|
|
|
118
99
|
// Command for creating a paragraph (pretty useless)
|
|
119
100
|
paragraph: new SlashMenuItem(
|
|
120
101
|
"Paragraph",
|
|
121
|
-
|
|
122
|
-
(editor, range) => {
|
|
102
|
+
(editor: Editor, range: Range) => {
|
|
123
103
|
return editor
|
|
124
104
|
.chain()
|
|
125
105
|
.focus()
|
|
126
106
|
.deleteRange(range)
|
|
127
|
-
.
|
|
107
|
+
.BNCreateOrUpdateBlock(range.from, {
|
|
108
|
+
type: "paragraph",
|
|
109
|
+
props: {},
|
|
110
|
+
})
|
|
128
111
|
.run();
|
|
129
112
|
},
|
|
130
|
-
["p"]
|
|
131
|
-
"Used for the body of your document",
|
|
132
|
-
formatKeyboardShortcut("Mod-Alt-0")
|
|
113
|
+
["p"]
|
|
133
114
|
),
|
|
134
115
|
|
|
135
116
|
// replaceRangeWithNode(editor, range, node);
|