@blocknote/core 0.4.0 → 0.4.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.
Files changed (87) hide show
  1. package/dist/blocknote.js +12371 -12268
  2. package/dist/blocknote.js.map +1 -1
  3. package/dist/blocknote.umd.cjs +20 -20
  4. package/dist/blocknote.umd.cjs.map +1 -1
  5. package/dist/style.css +1 -1
  6. package/package.json +2 -2
  7. package/src/BlockNoteEditor.ts +237 -14
  8. package/src/BlockNoteExtensions.ts +19 -15
  9. package/src/api/blockManipulation/__snapshots__/blockManipulation.test.ts.snap +616 -0
  10. package/src/api/blockManipulation/blockManipulation.test.ts +172 -0
  11. package/src/api/blockManipulation/blockManipulation.ts +25 -14
  12. package/src/api/formatConversions/__snapshots__/formatConversions.test.ts.snap +346 -0
  13. package/src/api/formatConversions/formatConversions.test.ts +766 -0
  14. package/src/api/nodeConversions/__snapshots__/nodeConversions.test.ts.snap +268 -0
  15. package/src/api/nodeConversions/nodeConversions.test.ts +244 -0
  16. package/src/api/nodeConversions/nodeConversions.ts +167 -58
  17. package/src/api/nodeConversions/testUtil.ts +61 -0
  18. package/src/api/util/nodeUtil.ts +38 -0
  19. package/src/editor.module.css +1 -0
  20. package/src/extensions/Blocks/api/blockTypes.ts +14 -9
  21. package/src/extensions/Blocks/api/cursorPositionTypes.ts +2 -0
  22. package/src/extensions/Blocks/api/inlineContentTypes.ts +27 -36
  23. package/src/extensions/Blocks/nodes/Block.module.css +39 -36
  24. package/src/extensions/Blocks/nodes/BlockContainer.ts +15 -14
  25. package/src/extensions/DraggableBlocks/DraggableBlocksPlugin.ts +149 -87
  26. package/src/extensions/SlashMenu/BaseSlashMenuItem.ts +31 -0
  27. package/src/extensions/SlashMenu/SlashMenuExtension.ts +10 -7
  28. package/src/extensions/SlashMenu/{defaultSlashCommands.tsx → defaultSlashMenuItems.tsx} +59 -106
  29. package/src/extensions/SlashMenu/index.ts +3 -7
  30. package/src/index.ts +2 -3
  31. package/src/shared/plugins/suggestion/SuggestionItem.ts +2 -13
  32. package/src/shared/plugins/suggestion/SuggestionPlugin.ts +31 -18
  33. package/src/shared/utils.ts +6 -0
  34. package/types/src/BlockNoteEditor.d.ts +82 -8
  35. package/types/src/BlockNoteExtensions.d.ts +5 -4
  36. package/types/src/api/Editor.d.ts +26 -6
  37. package/types/src/api/blockManipulation/blockManipulation.d.ts +5 -5
  38. package/types/src/api/blockManipulation/blockManipulation.test.d.ts +1 -0
  39. package/types/src/api/formatConversions/formatConversions.test.d.ts +1 -0
  40. package/types/src/api/nodeConversions/nodeConversions.d.ts +11 -4
  41. package/types/src/api/nodeConversions/nodeConversions.test.d.ts +1 -0
  42. package/types/src/api/nodeConversions/testUtil.d.ts +2 -0
  43. package/types/src/api/util/nodeUtil.d.ts +8 -0
  44. package/types/src/extensions/Blocks/api/blockTypes.d.ts +10 -9
  45. package/types/src/extensions/Blocks/api/cursorPositionTypes.d.ts +2 -0
  46. package/types/src/extensions/Blocks/api/inlineContentTypes.d.ts +25 -19
  47. package/types/src/extensions/DraggableBlocks/DraggableBlocksPlugin.d.ts +15 -0
  48. package/types/src/extensions/SlashMenu/BaseSlashMenuItem.d.ts +20 -0
  49. package/types/src/extensions/SlashMenu/SlashMenuExtension.d.ts +4 -2
  50. package/types/src/extensions/SlashMenu/defaultSlashMenuItems.d.ts +5 -0
  51. package/types/src/extensions/SlashMenu/index.d.ts +3 -3
  52. package/types/src/index.d.ts +2 -3
  53. package/types/src/shared/plugins/suggestion/SuggestionItem.d.ts +3 -11
  54. package/types/src/shared/plugins/suggestion/SuggestionPlugin.d.ts +4 -4
  55. package/types/src/shared/utils.d.ts +3 -0
  56. package/src/api/Editor.ts +0 -142
  57. package/src/extensions/SlashMenu/SlashMenuItem.ts +0 -34
  58. package/types/src/EditorElement.d.ts +0 -7
  59. package/types/src/api/Document.d.ts +0 -5
  60. package/types/src/api/removeUnderlinesRehypePlugin.d.ts +0 -6
  61. package/types/src/api/simplifyBlocksRehypePlugin.d.ts +0 -16
  62. package/types/src/extensions/Blocks/BlockAttributes.d.ts +0 -2
  63. package/types/src/extensions/Blocks/MultipleNodeSelection.d.ts +0 -24
  64. package/types/src/extensions/Blocks/api/apiTypes.d.ts +0 -18
  65. package/types/src/extensions/Blocks/api/styleTypes.d.ts +0 -22
  66. package/types/src/extensions/Blocks/apiTypes.d.ts +0 -16
  67. package/types/src/extensions/Blocks/nodes/Block.d.ts +0 -24
  68. package/types/src/extensions/Blocks/nodes/BlockContent/BlockContentTypes.d.ts +0 -4
  69. package/types/src/extensions/Blocks/nodes/BlockContent/HeadingBlockContent/HeadingBlockContentTypes.d.ts +0 -4
  70. package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContentTypes.d.ts +0 -2
  71. package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContentTypes.d.ts +0 -2
  72. package/types/src/extensions/Blocks/nodes/BlockContent/ParagraphBlockContent/ParagraphBlockContentTypes.d.ts +0 -2
  73. package/types/src/extensions/Blocks/nodes/BlockTypes/HeadingBlock/HeadingContent.d.ts +0 -8
  74. package/types/src/extensions/Blocks/nodes/BlockTypes/ListItemBlock/ListItemContent.d.ts +0 -8
  75. package/types/src/extensions/Blocks/nodes/BlockTypes/ListItemBlock/OrderedListItemIndexPlugin.d.ts +0 -2
  76. package/types/src/extensions/Blocks/nodes/BlockTypes/TextBlock/TextContent.d.ts +0 -6
  77. package/types/src/extensions/BubbleMenu/BubbleMenuExtension.d.ts +0 -8
  78. package/types/src/extensions/BubbleMenu/BubbleMenuFactoryTypes.d.ts +0 -27
  79. package/types/src/extensions/BubbleMenu/BubbleMenuPlugin.d.ts +0 -44
  80. package/types/src/extensions/DraggableBlocks/BlockMenuFactoryTypes.d.ts +0 -12
  81. package/types/src/extensions/DraggableBlocks/DragMenuFactoryTypes.d.ts +0 -18
  82. package/types/src/extensions/Hyperlinks/HyperlinkMark.d.ts +0 -8
  83. package/types/src/extensions/Hyperlinks/HyperlinkMenuFactoryTypes.d.ts +0 -11
  84. package/types/src/extensions/Hyperlinks/HyperlinkMenuPlugin.d.ts +0 -11
  85. package/types/src/extensions/Paragraph/FixedParagraph.d.ts +0 -1
  86. package/types/src/extensions/SlashMenu/defaultCommands.d.ts +0 -8
  87. package/types/src/utils.d.ts +0 -2
@@ -1,7 +1,10 @@
1
1
  import { mergeAttributes, Node } from "@tiptap/core";
2
2
  import { Fragment, Node as PMNode, Slice } from "prosemirror-model";
3
3
  import { TextSelection } from "prosemirror-state";
4
- import { blockToNode } from "../../../api/nodeConversions/nodeConversions";
4
+ import {
5
+ blockToNode,
6
+ inlineContentToNodes,
7
+ } from "../../../api/nodeConversions/nodeConversions";
5
8
  import { PartialBlock } from "../api/blockTypes";
6
9
  import { getBlockInfoFromPos } from "../helpers/getBlockInfoFromPos";
7
10
  import { PreviousBlockTypePlugin } from "../PreviousBlockTypePlugin";
@@ -329,15 +332,7 @@ export const BlockContainer = Node.create<IBlock>({
329
332
  } else {
330
333
  // Adds a text node with the provided styles converted into marks to the content, for each InlineContent
331
334
  // object.
332
- for (const styledText of block.content) {
333
- const marks = [];
334
-
335
- for (const style of styledText.styles) {
336
- marks.push(state.schema.mark(style.type, style.props));
337
- }
338
-
339
- content.push(state.schema.text(styledText.text, marks));
340
- }
335
+ content = inlineContentToNodes(block.content, state.schema);
341
336
  }
342
337
 
343
338
  // Replaces the contents of the blockContent node with the previously created text node(s).
@@ -350,10 +345,16 @@ export const BlockContainer = Node.create<IBlock>({
350
345
 
351
346
  // Changes the block type and adds the provided props as node attributes. Also preserves all existing node
352
347
  // attributes that are compatible with the new type.
353
- state.tr.setNodeMarkup(startPos, state.schema.nodes[block.type], {
354
- ...contentNode.attrs,
355
- ...block.props,
356
- });
348
+ state.tr.setNodeMarkup(
349
+ startPos,
350
+ block.type === undefined
351
+ ? undefined
352
+ : state.schema.nodes[block.type],
353
+ {
354
+ ...contentNode.attrs,
355
+ ...block.props,
356
+ }
357
+ );
357
358
  }
358
359
 
359
360
  return true;
@@ -150,8 +150,10 @@ function setDragImage(view: EditorView, from: number, to = from) {
150
150
  }
151
151
 
152
152
  // dataTransfer.setDragImage(element) only works if element is attached to the DOM.
153
+ unsetDragImage();
153
154
  dragImageElement = parentClone;
154
- dragImageElement.className = styles.dragPreview;
155
+ dragImageElement.className =
156
+ dragImageElement.className + " " + styles.dragPreview;
155
157
  document.body.appendChild(dragImageElement);
156
158
  }
157
159
 
@@ -245,104 +247,164 @@ export class BlockMenuView {
245
247
 
246
248
  this.blockMenu = blockMenuFactory(this.getStaticParams());
247
249
 
250
+ document.body.addEventListener("drop", this.onDrop, true);
251
+ document.body.addEventListener("dragover", this.onDragOver);
252
+
248
253
  // Shows or updates menu position whenever the cursor moves, if the menu isn't frozen.
249
- document.body.addEventListener(
250
- "mousemove",
251
- (event) => {
252
- if (this.menuFrozen) {
253
- return;
254
- }
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
-
264
- // Gets block at mouse cursor's vertical position.
265
- const coords = {
266
- left: editorBoundingBox.left + editorBoundingBox.width / 2, // take middle of editor
267
- top: event.clientY,
268
- };
269
- const block = getDraggableBlockFromCoords(coords, this.editor.view);
270
-
271
- // Closes the menu if the mouse cursor is beyond the editor vertically.
272
- if (!block) {
273
- if (this.menuOpen) {
274
- this.menuOpen = false;
275
- this.blockMenu.hide();
276
- }
277
-
278
- return;
279
- }
280
-
281
- // Doesn't update if the menu is already open and the mouse cursor is still hovering the same block.
282
- if (
283
- this.menuOpen &&
284
- this.hoveredBlockContent?.hasAttribute("data-id") &&
285
- this.hoveredBlockContent?.getAttribute("data-id") === block.id
286
- ) {
287
- return;
288
- }
289
-
290
- // Gets the block's content node, which lets to ignore child blocks when determining the block menu's position.
291
- const blockContent = block.node.firstChild as HTMLElement;
292
- this.hoveredBlockContent = blockContent;
293
-
294
- if (!blockContent) {
295
- return;
296
- }
297
-
298
- // Shows or updates elements.
299
- if (!this.menuOpen) {
300
- this.menuOpen = true;
301
- this.blockMenu.render(this.getDynamicParams(), true);
302
- } else {
303
- this.blockMenu.render(this.getDynamicParams(), false);
304
- }
305
- },
306
- true
307
- );
254
+ document.body.addEventListener("mousemove", this.onMouseMove, true);
308
255
 
309
256
  // Hides and unfreezes the menu whenever the user selects the editor with the mouse or presses a key.
310
257
  // TODO: Better integration with suggestions menu and only editor scope?
311
- document.body.addEventListener(
312
- "mousedown",
313
- (event) => {
314
- if (this.blockMenu.element?.contains(event.target as HTMLElement)) {
315
- return;
316
- }
317
-
318
- if (this.menuOpen) {
319
- this.menuOpen = false;
320
- this.blockMenu.hide();
321
- }
258
+ document.body.addEventListener("mousedown", this.onMouseDown, true);
259
+ document.body.addEventListener("keydown", this.onKeyDown, true);
260
+ }
322
261
 
323
- this.menuFrozen = false;
324
- },
325
- true
326
- );
327
- document.body.addEventListener(
328
- "keydown",
329
- () => {
330
- if (this.menuOpen) {
331
- this.menuOpen = false;
332
- this.blockMenu.hide();
333
- }
262
+ /**
263
+ * If the event is outside of the editor contents,
264
+ * we dispatch a fake event, so that we can still drop the content
265
+ * when dragging / dropping to the side of the editor
266
+ */
267
+ onDrop = (event: DragEvent) => {
268
+ if ((event as any).synthetic) {
269
+ return;
270
+ }
271
+ let pos = this.editor.view.posAtCoords({
272
+ left: event.clientX,
273
+ top: event.clientY,
274
+ });
334
275
 
335
- this.menuFrozen = false;
336
- },
337
- true
338
- );
339
- }
276
+ if (!pos || pos.inside === -1) {
277
+ const evt = new Event("drop", event) as any;
278
+ const editorBoundingBox = (
279
+ this.editor.view.dom.firstChild! as HTMLElement
280
+ ).getBoundingClientRect();
281
+ evt.clientX = editorBoundingBox.left + editorBoundingBox.width / 2;
282
+ evt.clientY = event.clientY;
283
+ evt.dataTransfer = event.dataTransfer;
284
+ evt.preventDefault = () => event.preventDefault();
285
+ evt.synthetic = true; // prevent recursion
286
+ // console.log("dispatch fake drop");
287
+ this.editor.view.dom.dispatchEvent(evt);
288
+ }
289
+ };
290
+
291
+ /**
292
+ * If the event is outside of the editor contents,
293
+ * we dispatch a fake event, so that we can still drop the content
294
+ * when dragging / dropping to the side of the editor
295
+ */
296
+ onDragOver = (event: DragEvent) => {
297
+ if ((event as any).synthetic) {
298
+ return;
299
+ }
300
+ let pos = this.editor.view.posAtCoords({
301
+ left: event.clientX,
302
+ top: event.clientY,
303
+ });
304
+
305
+ if (!pos || pos.inside === -1) {
306
+ const evt = new Event("dragover", event) as any;
307
+ const editorBoundingBox = (
308
+ this.editor.view.dom.firstChild! as HTMLElement
309
+ ).getBoundingClientRect();
310
+ evt.clientX = editorBoundingBox.left + editorBoundingBox.width / 2;
311
+ evt.clientY = event.clientY;
312
+ evt.dataTransfer = event.dataTransfer;
313
+ evt.preventDefault = () => event.preventDefault();
314
+ evt.synthetic = true; // prevent recursion
315
+ // console.log("dispatch fake dragover");
316
+ this.editor.view.dom.dispatchEvent(evt);
317
+ }
318
+ };
319
+
320
+ onKeyDown = (_event: KeyboardEvent) => {
321
+ if (this.menuOpen) {
322
+ this.menuOpen = false;
323
+ this.blockMenu.hide();
324
+ }
325
+
326
+ this.menuFrozen = false;
327
+ };
328
+
329
+ onMouseDown = (event: MouseEvent) => {
330
+ if (this.blockMenu.element?.contains(event.target as HTMLElement)) {
331
+ return;
332
+ }
333
+
334
+ if (this.menuOpen) {
335
+ this.menuOpen = false;
336
+ this.blockMenu.hide();
337
+ }
338
+
339
+ this.menuFrozen = false;
340
+ };
341
+
342
+ onMouseMove = (event: MouseEvent) => {
343
+ if (this.menuFrozen) {
344
+ return;
345
+ }
346
+
347
+ // Editor itself may have padding or other styling which affects size/position, so we get the boundingRect of
348
+ // the first child (i.e. the blockGroup that wraps all blocks in the editor) for a more accurate bounding box.
349
+ const editorBoundingBox = (
350
+ this.editor.view.dom.firstChild! as HTMLElement
351
+ ).getBoundingClientRect();
352
+
353
+ this.horizontalPosAnchor = editorBoundingBox.x;
354
+
355
+ // Gets block at mouse cursor's vertical position.
356
+ const coords = {
357
+ left: editorBoundingBox.left + editorBoundingBox.width / 2, // take middle of editor
358
+ top: event.clientY,
359
+ };
360
+ const block = getDraggableBlockFromCoords(coords, this.editor.view);
361
+
362
+ // Closes the menu if the mouse cursor is beyond the editor vertically.
363
+ if (!block) {
364
+ if (this.menuOpen) {
365
+ this.menuOpen = false;
366
+ this.blockMenu.hide();
367
+ }
368
+
369
+ return;
370
+ }
371
+
372
+ // Doesn't update if the menu is already open and the mouse cursor is still hovering the same block.
373
+ if (
374
+ this.menuOpen &&
375
+ this.hoveredBlockContent?.hasAttribute("data-id") &&
376
+ this.hoveredBlockContent?.getAttribute("data-id") === block.id
377
+ ) {
378
+ return;
379
+ }
380
+
381
+ // Gets the block's content node, which lets to ignore child blocks when determining the block menu's position.
382
+ const blockContent = block.node.firstChild as HTMLElement;
383
+ this.hoveredBlockContent = blockContent;
384
+
385
+ if (!blockContent) {
386
+ return;
387
+ }
388
+
389
+ // Shows or updates elements.
390
+ if (!this.menuOpen) {
391
+ this.menuOpen = true;
392
+ this.blockMenu.render(this.getDynamicParams(), true);
393
+ } else {
394
+ this.blockMenu.render(this.getDynamicParams(), false);
395
+ }
396
+ };
340
397
 
341
398
  destroy() {
342
399
  if (this.menuOpen) {
343
400
  this.menuOpen = false;
344
401
  this.blockMenu.hide();
345
402
  }
403
+ document.body.removeEventListener("mousemove", this.onMouseMove);
404
+ document.body.removeEventListener("dragover", this.onDragOver);
405
+ document.body.removeEventListener("drop", this.onDrop);
406
+ document.body.removeEventListener("mousedown", this.onMouseDown);
407
+ document.body.removeEventListener("keydown", this.onKeyDown);
346
408
  }
347
409
 
348
410
  addBlock() {
@@ -0,0 +1,31 @@
1
+ import { SuggestionItem } from "../../shared/plugins/suggestion/SuggestionItem";
2
+ import { BlockNoteEditor } from "../../BlockNoteEditor";
3
+
4
+ /**
5
+ * A class that defines a slash command (/<command>).
6
+ *
7
+ * (Not to be confused with ProseMirror commands nor TipTap commands.)
8
+ */
9
+ export class BaseSlashMenuItem extends SuggestionItem {
10
+ /**
11
+ * Constructs a new slash-command.
12
+ *
13
+ * @param name The name of the command
14
+ * @param execute The callback for creating a new node
15
+ * @param aliases Aliases for this command
16
+ */
17
+ constructor(
18
+ public readonly name: string,
19
+ public readonly execute: (editor: BlockNoteEditor) => void,
20
+ public readonly aliases: string[] = []
21
+ ) {
22
+ super(name, (query: string): boolean => {
23
+ return (
24
+ this.name.toLowerCase().startsWith(query.toLowerCase()) ||
25
+ this.aliases.filter((alias) =>
26
+ alias.toLowerCase().startsWith(query.toLowerCase())
27
+ ).length !== 0
28
+ );
29
+ });
30
+ }
31
+ }
@@ -2,10 +2,12 @@ import { Extension } from "@tiptap/core";
2
2
  import { PluginKey } from "prosemirror-state";
3
3
  import { createSuggestionPlugin } from "../../shared/plugins/suggestion/SuggestionPlugin";
4
4
  import { SuggestionsMenuFactory } from "../../shared/plugins/suggestion/SuggestionsMenuFactoryTypes";
5
- import { SlashMenuItem } from "./SlashMenuItem";
5
+ import { BaseSlashMenuItem } from "./BaseSlashMenuItem";
6
+ import { BlockNoteEditor } from "../../BlockNoteEditor";
6
7
 
7
8
  export type SlashMenuOptions = {
8
- commands: SlashMenuItem[] | undefined;
9
+ editor: BlockNoteEditor | undefined;
10
+ commands: BaseSlashMenuItem[] | undefined;
9
11
  slashMenuFactory: SuggestionsMenuFactory<any> | undefined;
10
12
  };
11
13
 
@@ -16,6 +18,7 @@ export const SlashMenuExtension = Extension.create<SlashMenuOptions>({
16
18
 
17
19
  addOptions() {
18
20
  return {
21
+ editor: undefined,
19
22
  commands: undefined,
20
23
  slashMenuFactory: undefined,
21
24
  };
@@ -29,16 +32,16 @@ export const SlashMenuExtension = Extension.create<SlashMenuOptions>({
29
32
  const commands = this.options.commands;
30
33
 
31
34
  return [
32
- createSuggestionPlugin<SlashMenuItem>({
35
+ createSuggestionPlugin<BaseSlashMenuItem>({
33
36
  pluginKey: SlashMenuPluginKey,
34
- editor: this.editor,
37
+ editor: this.options.editor!,
35
38
  defaultTriggerCharacter: "/",
36
39
  suggestionsMenuFactory: this.options.slashMenuFactory!,
37
40
  items: (query) => {
38
- return commands.filter((cmd: SlashMenuItem) => cmd.match(query));
41
+ return commands.filter((cmd: BaseSlashMenuItem) => cmd.match(query));
39
42
  },
40
- onSelectItem: ({ item, editor, range }) => {
41
- item.execute(editor, range);
43
+ onSelectItem: ({ item, editor }) => {
44
+ item.execute(editor);
42
45
  },
43
46
  }),
44
47
  ];
@@ -1,135 +1,88 @@
1
- import { Editor, Range } from "@tiptap/core";
2
- import { formatKeyboardShortcut } from "../../shared/utils";
3
- import { SlashMenuItem } from "./SlashMenuItem";
1
+ import { BaseSlashMenuItem } from "./BaseSlashMenuItem";
2
+ import { PartialBlock } from "../Blocks/api/blockTypes";
3
+ import { BlockNoteEditor } from "../../BlockNoteEditor";
4
+
5
+ function insertOrUpdateBlock(editor: BlockNoteEditor, block: PartialBlock) {
6
+ const currentBlock = editor.getTextCursorPosition().block;
7
+
8
+ if (
9
+ (currentBlock.content.length === 1 &&
10
+ currentBlock.content[0].type === "text" &&
11
+ currentBlock.content[0].text === "/") ||
12
+ currentBlock.content.length === 0
13
+ ) {
14
+ editor.updateBlock(currentBlock, block);
15
+ } else {
16
+ editor.insertBlocks([block], currentBlock, "after");
17
+ editor.setTextCursorPosition(editor.getTextCursorPosition().nextBlock!);
18
+ }
19
+ }
4
20
 
5
21
  /**
6
22
  * An array containing commands for creating all default blocks.
7
23
  */
8
- export const defaultSlashCommands: SlashMenuItem[] = [
24
+ export const defaultSlashMenuItems: BaseSlashMenuItem[] = [
9
25
  // Command for creating a level 1 heading
10
- new SlashMenuItem(
26
+ new BaseSlashMenuItem(
11
27
  "Heading",
12
- (editor: Editor, range: Range) => {
13
- return editor
14
- .chain()
15
- .focus()
16
- .deleteRange(range)
17
- .BNCreateOrUpdateBlock(range.from, {
18
- type: "heading",
19
- props: {
20
- level: "1",
21
- },
22
- })
23
- .run();
24
- },
25
- ["h", "heading1", "h1"],
26
- "Headings",
27
- "Used for a top-level heading",
28
- formatKeyboardShortcut("Mod-Alt-1")
28
+ (editor) =>
29
+ insertOrUpdateBlock(editor, {
30
+ type: "heading",
31
+ props: { level: "1" },
32
+ }),
33
+ ["h", "heading1", "h1"]
29
34
  ),
30
35
 
31
36
  // Command for creating a level 2 heading
32
- new SlashMenuItem(
37
+ new BaseSlashMenuItem(
33
38
  "Heading 2",
34
- (editor: Editor, range: Range) => {
35
- return editor
36
- .chain()
37
- .focus()
38
- .deleteRange(range)
39
- .BNCreateOrUpdateBlock(range.from, {
40
- type: "heading",
41
- props: {
42
- level: "2",
43
- },
44
- })
45
- .run();
46
- },
47
- ["h2", "heading2", "subheading"],
48
- "Headings",
49
- "Used for key sections",
50
- formatKeyboardShortcut("Mod-Alt-2")
39
+ (editor) =>
40
+ insertOrUpdateBlock(editor, {
41
+ type: "heading",
42
+ props: { level: "2" },
43
+ }),
44
+ ["h2", "heading2", "subheading"]
51
45
  ),
52
46
 
53
47
  // Command for creating a level 3 heading
54
- new SlashMenuItem(
48
+ new BaseSlashMenuItem(
55
49
  "Heading 3",
56
- (editor: Editor, range: Range) => {
57
- return editor
58
- .chain()
59
- .focus()
60
- .deleteRange(range)
61
- .BNCreateOrUpdateBlock(range.from, {
62
- type: "heading",
63
- props: {
64
- level: "3",
65
- },
66
- })
67
- .run();
68
- },
69
- ["h3", "heading3", "subheading"],
70
- "Headings",
71
- "Used for subsections and group headings",
72
- formatKeyboardShortcut("Mod-Alt-3")
50
+ (editor) =>
51
+ insertOrUpdateBlock(editor, {
52
+ type: "heading",
53
+ props: { level: "3" },
54
+ }),
55
+ ["h3", "heading3", "subheading"]
73
56
  ),
74
57
 
75
58
  // Command for creating an ordered list
76
- new SlashMenuItem(
59
+ new BaseSlashMenuItem(
77
60
  "Numbered List",
78
- (editor: Editor, range: Range) => {
79
- return editor
80
- .chain()
81
- .focus()
82
- .deleteRange(range)
83
- .BNCreateOrUpdateBlock(range.from, {
84
- type: "numberedListItem",
85
- props: {},
86
- })
87
- .run();
88
- },
89
- ["li", "list", "numberedlist", "numbered list"],
90
- "Basic blocks",
91
- "Used to display a numbered list",
92
- "Mod-Alt-7"
61
+ (editor) =>
62
+ insertOrUpdateBlock(editor, {
63
+ type: "numberedListItem",
64
+ }),
65
+ ["li", "list", "numberedlist", "numbered list"]
93
66
  ),
94
67
 
95
68
  // Command for creating a bullet list
96
- new SlashMenuItem(
69
+ new BaseSlashMenuItem(
97
70
  "Bullet List",
98
- (editor: Editor, range: Range) => {
99
- return editor
100
- .chain()
101
- .focus()
102
- .deleteRange(range)
103
- .BNCreateOrUpdateBlock(range.from, {
104
- type: "bulletListItem",
105
- props: {},
106
- })
107
- .run();
108
- },
109
- ["ul", "list", "bulletlist", "bullet list"],
110
- "Basic blocks",
111
- "Used to display an unordered list",
112
- "Mod-Alt-9"
71
+ (editor) =>
72
+ insertOrUpdateBlock(editor, {
73
+ type: "bulletListItem",
74
+ }),
75
+ ["ul", "list", "bulletlist", "bullet list"]
113
76
  ),
114
77
 
115
78
  // Command for creating a paragraph (pretty useless)
116
- new SlashMenuItem(
79
+ new BaseSlashMenuItem(
117
80
  "Paragraph",
118
- (editor: Editor, range: Range) => {
119
- return editor
120
- .chain()
121
- .focus()
122
- .deleteRange(range)
123
- .BNCreateOrUpdateBlock(range.from, {
124
- type: "paragraph",
125
- props: {},
126
- })
127
- .run();
128
- },
129
- ["p"],
130
- "Basic blocks",
131
- "Used for the body of your document",
132
- "Mod-Alt-0"
81
+ (editor) =>
82
+ insertOrUpdateBlock(editor, {
83
+ type: "paragraph",
84
+ }),
85
+ ["p"]
133
86
  ),
134
87
 
135
88
  // replaceRangeWithNode(editor, range, node);
@@ -1,9 +1,5 @@
1
- import { defaultSlashCommands } from "./defaultSlashCommands";
1
+ import { defaultSlashMenuItems } from "./defaultSlashMenuItems";
2
2
  import { SlashMenuExtension } from "./SlashMenuExtension";
3
- import { SlashMenuItem } from "./SlashMenuItem";
3
+ import { BaseSlashMenuItem } from "./BaseSlashMenuItem";
4
4
 
5
- export {
6
- defaultSlashCommands,
7
- SlashMenuItem as SlashCommand,
8
- SlashMenuExtension,
9
- };
5
+ export { defaultSlashMenuItems, BaseSlashMenuItem, SlashMenuExtension };
package/src/index.ts CHANGED
@@ -4,9 +4,8 @@ export * from "./extensions/Blocks/api/blockTypes";
4
4
  export * from "./extensions/DraggableBlocks/BlockSideMenuFactoryTypes";
5
5
  export * from "./extensions/FormattingToolbar/FormattingToolbarFactoryTypes";
6
6
  export * from "./extensions/HyperlinkToolbar/HyperlinkToolbarFactoryTypes";
7
- export { defaultSlashCommands } from "./extensions/SlashMenu/defaultSlashCommands";
8
- export * from "./extensions/SlashMenu/SlashMenuItem";
7
+ export { defaultSlashMenuItems } from "./extensions/SlashMenu/defaultSlashMenuItems";
8
+ export * from "./extensions/SlashMenu/BaseSlashMenuItem";
9
9
  export * from "./shared/EditorElement";
10
10
  export type { SuggestionItem } from "./shared/plugins/suggestion/SuggestionItem";
11
11
  export * from "./shared/plugins/suggestion/SuggestionsMenuFactoryTypes";
12
- export * from "../src/api/Editor";
@@ -1,17 +1,6 @@
1
1
  /**
2
2
  * A generic interface used in all suggestion menus (slash menu, mentions, etc)
3
3
  */
4
- export interface SuggestionItem {
5
- /**
6
- * The name of the item
7
- */
8
- name: string;
9
-
10
- /**
11
- * This function matches this item against a query string, the function should return **true** if the item
12
- * matches the query or **false** otherwise.
13
- *
14
- * @param query the query string
15
- */
16
- match(query: string): boolean;
4
+ export class SuggestionItem {
5
+ constructor(public name: string, public match: (query: string) => boolean) {}
17
6
  }