@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.
Files changed (89) hide show
  1. package/dist/blocknote.js +1061 -936
  2. package/dist/blocknote.js.map +1 -1
  3. package/dist/blocknote.umd.cjs +1 -1
  4. package/dist/blocknote.umd.cjs.map +1 -1
  5. package/dist/style.css +1 -1
  6. package/package.json +22 -29
  7. package/src/BlockNoteExtensions.ts +11 -10
  8. package/src/extensions/BackgroundColor/BackgroundColorExtension.ts +61 -0
  9. package/src/extensions/BackgroundColor/BackgroundColorMark.ts +62 -0
  10. package/src/extensions/Blocks/PreviousBlockTypePlugin.ts +112 -106
  11. package/src/extensions/Blocks/apiTypes.ts +48 -0
  12. package/src/extensions/Blocks/helpers/findBlock.ts +3 -1
  13. package/src/extensions/Blocks/helpers/getBlockInfoFromPos.ts +1 -1
  14. package/src/extensions/Blocks/index.ts +10 -8
  15. package/src/extensions/Blocks/nodes/Block.module.css +122 -35
  16. package/src/extensions/Blocks/{BlockAttributes.ts → nodes/BlockAttributes.ts} +0 -0
  17. package/src/extensions/Blocks/nodes/{Block.ts → BlockContainer.ts} +113 -119
  18. package/src/extensions/Blocks/nodes/{BlockTypes/HeadingBlock/HeadingContent.ts → BlockContent/HeadingBlockContent/HeadingBlockContent.ts} +16 -24
  19. package/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts +76 -0
  20. package/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/ListItemKeyboardShortcuts.ts +47 -0
  21. package/src/extensions/Blocks/nodes/{BlockTypes/ListItemBlock/OrderedListItemIndexPlugin.ts → BlockContent/ListItemBlockContent/NumberedListItemBlockContent/NumberedListIndexingPlugin.ts} +10 -14
  22. package/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts +95 -0
  23. package/src/extensions/Blocks/nodes/{BlockTypes/TextBlock/TextContent.ts → BlockContent/ParagraphBlockContent/ParagraphBlockContent.ts} +7 -12
  24. package/src/extensions/Blocks/nodes/BlockGroup.ts +4 -4
  25. package/src/extensions/DraggableBlocks/BlockSideMenuFactoryTypes.ts +9 -1
  26. package/src/extensions/DraggableBlocks/DraggableBlocksPlugin.ts +87 -42
  27. package/src/extensions/{Blocks → DraggableBlocks}/MultipleNodeSelection.ts +0 -0
  28. package/src/extensions/FormattingToolbar/FormattingToolbarFactoryTypes.ts +20 -7
  29. package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +51 -12
  30. package/src/extensions/HyperlinkToolbar/HyperlinkToolbarFactoryTypes.ts +1 -1
  31. package/src/extensions/HyperlinkToolbar/HyperlinkToolbarPlugin.ts +3 -1
  32. package/src/extensions/Placeholder/PlaceholderExtension.ts +1 -1
  33. package/src/extensions/SlashMenu/SlashMenuExtension.ts +1 -1
  34. package/src/extensions/SlashMenu/SlashMenuItem.ts +3 -28
  35. package/src/extensions/SlashMenu/defaultCommands.tsx +36 -55
  36. package/src/extensions/SlashMenu/index.ts +1 -6
  37. package/src/extensions/TextAlignment/TextAlignmentExtension.ts +75 -0
  38. package/src/extensions/TextColor/TextColorExtension.ts +54 -0
  39. package/src/extensions/TextColor/TextColorMark.ts +62 -0
  40. package/src/extensions/TrailingNode/TrailingNodeExtension.ts +4 -4
  41. package/src/extensions/UniqueID/UniqueID.ts +6 -0
  42. package/src/index.ts +2 -1
  43. package/src/shared/EditorElement.ts +12 -6
  44. package/src/shared/plugins/suggestion/SuggestionItem.ts +0 -9
  45. package/src/shared/plugins/suggestion/SuggestionPlugin.ts +191 -228
  46. package/src/shared/plugins/suggestion/SuggestionsMenuFactoryTypes.ts +2 -2
  47. package/types/src/BlockNoteEditor.d.ts +1 -1
  48. package/types/src/BlockNoteExtensions.d.ts +1 -3
  49. package/types/src/api/Document.d.ts +5 -0
  50. package/types/src/extensions/BackgroundColor/BackgroundColorExtension.d.ts +9 -0
  51. package/types/src/extensions/BackgroundColor/BackgroundColorMark.d.ts +9 -0
  52. package/types/src/extensions/Blocks/PreviousBlockTypePlugin.d.ts +3 -2
  53. package/types/src/extensions/Blocks/apiTypes.d.ts +16 -0
  54. package/types/src/extensions/Blocks/helpers/getBlockInfoFromPos.d.ts +1 -1
  55. package/types/src/extensions/Blocks/nodes/BlockAttributes.d.ts +2 -0
  56. package/types/src/extensions/Blocks/nodes/BlockContainer.d.ts +21 -0
  57. package/types/src/extensions/Blocks/nodes/BlockContent/BlockContentTypes.d.ts +4 -0
  58. package/types/src/extensions/Blocks/nodes/BlockContent/HeadingBlockContent/HeadingBlockContent.d.ts +2 -0
  59. package/types/src/extensions/Blocks/nodes/BlockContent/HeadingBlockContent/HeadingBlockContentTypes.d.ts +4 -0
  60. package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.d.ts +2 -0
  61. package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContentTypes.d.ts +2 -0
  62. package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/ListItemKeyboardShortcuts.d.ts +2 -0
  63. package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/NumberedListItemBlockContent/NumberedListIndexingPlugin.d.ts +2 -0
  64. package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.d.ts +2 -0
  65. package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContentTypes.d.ts +2 -0
  66. package/types/src/extensions/Blocks/nodes/BlockContent/ParagraphBlockContent/ParagraphBlockContent.d.ts +2 -0
  67. package/types/src/extensions/Blocks/nodes/BlockContent/ParagraphBlockContent/ParagraphBlockContentTypes.d.ts +2 -0
  68. package/types/src/extensions/DraggableBlocks/BlockSideMenuFactoryTypes.d.ts +9 -5
  69. package/types/src/extensions/DraggableBlocks/DraggableBlocksExtension.d.ts +1 -1
  70. package/types/src/extensions/DraggableBlocks/DraggableBlocksPlugin.d.ts +6 -11
  71. package/types/src/extensions/DraggableBlocks/MultipleNodeSelection.d.ts +24 -0
  72. package/types/src/extensions/FormattingToolbar/FormattingToolbarFactoryTypes.d.ts +18 -8
  73. package/types/src/extensions/FormattingToolbar/FormattingToolbarPlugin.d.ts +1 -1
  74. package/types/src/extensions/HyperlinkToolbar/HyperlinkToolbarFactoryTypes.d.ts +5 -5
  75. package/types/src/extensions/HyperlinkToolbar/HyperlinkToolbarPlugin.d.ts +2 -2
  76. package/types/src/extensions/SlashMenu/SlashMenuExtension.d.ts +1 -1
  77. package/types/src/extensions/SlashMenu/SlashMenuItem.d.ts +2 -19
  78. package/types/src/extensions/SlashMenu/defaultSlashCommands.d.ts +5 -0
  79. package/types/src/extensions/SlashMenu/index.d.ts +1 -2
  80. package/types/src/extensions/TextAlignment/TextAlignmentExtension.d.ts +9 -0
  81. package/types/src/extensions/TextColor/TextColorExtension.d.ts +9 -0
  82. package/types/src/extensions/TextColor/TextColorMark.d.ts +9 -0
  83. package/types/src/index.d.ts +2 -1
  84. package/types/src/shared/EditorElement.d.ts +6 -2
  85. package/types/src/shared/plugins/suggestion/SuggestionItem.d.ts +0 -6
  86. package/types/src/shared/plugins/suggestion/SuggestionPlugin.d.ts +11 -25
  87. package/types/src/shared/plugins/suggestion/SuggestionsMenuFactoryTypes.d.ts +6 -6
  88. package/src/extensions/Blocks/nodes/BlockTypes/ListItemBlock/ListItemContent.ts +0 -177
  89. 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 { MultipleNodeSelection } from "../Blocks/MultipleNodeSelection";
7
- import { DraggableBlocksOptions } from "./DraggableBlocksExtension";
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 { getBlockInfoFromPos } from "../Blocks/helpers/getBlockInfoFromPos";
15
- import { SlashMenuPluginKey } from "../SlashMenu/SlashMenuExtension";
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: view.dom.clientWidth / 2, // take middle of editor
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
- hoveredBlock: HTMLElement | undefined;
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: this.editor.view.dom.clientWidth / 2, // take middle of editor
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.hoveredBlock?.hasAttribute("data-id") &&
287
- this.hoveredBlock?.getAttribute("data-id") === block.id
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.hoveredBlock = blockContent;
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 blockBoundingBox = this.hoveredBlock!.getBoundingClientRect();
353
+ const blockContentBoundingBox =
354
+ this.hoveredBlockContent!.getBoundingClientRect();
356
355
 
357
356
  const pos = this.editor.view.posAtCoords({
358
- left: blockBoundingBox.left,
359
- top: blockBoundingBox.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
- .BNSetContentType(newBlockContentPos, { name: "textContent" })
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 blockBoundingBox = this.hoveredBlock!.getBoundingClientRect();
401
+ const blockContentBoundingBox =
402
+ this.hoveredBlockContent!.getBoundingClientRect();
401
403
 
402
404
  const pos = this.editor.view.posAtCoords({
403
- left: blockBoundingBox.left,
404
- top: blockBoundingBox.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 blockBoundingBox = this.hoveredBlock!.getBoundingClientRect();
470
+ const blockContentBoundingBox =
471
+ this.hoveredBlockContent!.getBoundingClientRect();
430
472
 
431
473
  return {
432
- blockBoundingBox: new DOMRect(
474
+ blockBackgroundColor:
475
+ this.editor.getAttributes("blockContainer").backgroundColor,
476
+ blockTextColor: this.editor.getAttributes("blockContainer").textColor,
477
+ referenceRect: new DOMRect(
433
478
  this.horizontalPosAnchoredAtRoot
434
- ? getHorizontalAnchor()
435
- : blockBoundingBox.x,
436
- blockBoundingBox.y,
437
- blockBoundingBox.width,
438
- blockBoundingBox.height
479
+ ? this.horizontalPosAnchor
480
+ : blockContentBoundingBox.x,
481
+ blockContentBoundingBox.y,
482
+ blockContentBoundingBox.width,
483
+ blockContentBoundingBox.height
439
484
  ),
440
485
  };
441
486
  }
@@ -1,5 +1,5 @@
1
1
  import { EditorElement, ElementFactory } from "../../shared/EditorElement";
2
- import { BlockContentType } from "../Blocks/nodes/Block";
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
- setBlockType: (type: BlockContentType) => void;
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
- // BlockContentType is mostly used to set a block's type, so the attr field is optional as block content types have
24
- // default values for attributes. However, it means that a block type's attributes field will never be undefined due to
25
- // these default values, which the Required type enforces.
26
- activeBlockType: Required<BlockContentType>;
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
- selectionBoundingBox: DOMRect;
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
- setBlockType: (type: BlockContentType) => {
269
+ setTextColor: (color: string) => {
269
270
  this.editor.view.focus();
270
- this.editor.commands.BNSetContentType(
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
- type
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
- activeBlockType: {
293
- name: this.editor.state.selection.$from.node().type.name,
294
- attrs: this.editor.state.selection.$from.node().attrs,
295
- } as Required<BlockContentType>,
296
- selectionBoundingBox: this.getSelectionBoundingBox(),
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
  }
@@ -9,7 +9,7 @@ export type HyperlinkToolbarDynamicParams = {
9
9
  url: string;
10
10
  text: string;
11
11
 
12
- boundingBox: DOMRect;
12
+ referenceRect: DOMRect;
13
13
  };
14
14
 
15
15
  export type HyperlinkToolbar = EditorElement<HyperlinkToolbarDynamicParams>;
@@ -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
- boundingBox: posToDOMRect(
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?.type === "drag" && menuState?.active) {
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
- char: "/",
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 group: SlashMenuGroups,
40
- public readonly execute: SlashMenuCallback,
41
- public readonly aliases: string[] = [],
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 { formatKeyboardShortcut } from "../../shared/utils";
2
- import { SlashMenuGroups, SlashMenuItem } from "./SlashMenuItem";
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
- SlashMenuGroups.HEADINGS,
12
- (editor, range) => {
11
+ (editor: Editor, range: Range) => {
13
12
  return editor
14
13
  .chain()
15
14
  .focus()
16
15
  .deleteRange(range)
17
- .BNCreateBlockOrSetContentType(range.from, {
18
- name: "headingContent",
19
- attrs: {
20
- headingLevel: "1",
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
- SlashMenuGroups.HEADINGS,
34
- (editor, range) => {
30
+ (editor: Editor, range: Range) => {
35
31
  return editor
36
32
  .chain()
37
33
  .focus()
38
34
  .deleteRange(range)
39
- .BNCreateBlockOrSetContentType(range.from, {
40
- name: "headingContent",
41
- attrs: {
42
- headingLevel: "2",
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
- SlashMenuGroups.HEADINGS,
56
- (editor, range) => {
49
+ (editor: Editor, range: Range) => {
57
50
  return editor
58
51
  .chain()
59
52
  .focus()
60
53
  .deleteRange(range)
61
- .BNCreateBlockOrSetContentType(range.from, {
62
- name: "headingContent",
63
- attrs: {
64
- headingLevel: "3",
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
- SlashMenuGroups.BASIC_BLOCKS,
78
- (editor, range) => {
68
+ (editor: Editor, range: Range) => {
79
69
  return editor
80
70
  .chain()
81
71
  .focus()
82
72
  .deleteRange(range)
83
- .BNCreateBlockOrSetContentType(range.from, {
84
- name: "listItemContent",
85
- attrs: {
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
- SlashMenuGroups.BASIC_BLOCKS,
100
- (editor, range) => {
85
+ (editor: Editor, range: Range) => {
101
86
  return editor
102
87
  .chain()
103
88
  .focus()
104
89
  .deleteRange(range)
105
- .BNCreateBlockOrSetContentType(range.from, {
106
- name: "listItemContent",
107
- attrs: {
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
- SlashMenuGroups.BASIC_BLOCKS,
122
- (editor, range) => {
102
+ (editor: Editor, range: Range) => {
123
103
  return editor
124
104
  .chain()
125
105
  .focus()
126
106
  .deleteRange(range)
127
- .BNCreateBlockOrSetContentType(range.from, { name: "textContent" })
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);