@blocknote/core 0.7.0 → 0.8.0

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 (70) hide show
  1. package/dist/blocknote.js +1428 -1252
  2. package/dist/blocknote.js.map +1 -1
  3. package/dist/blocknote.umd.cjs +2 -2
  4. package/dist/blocknote.umd.cjs.map +1 -1
  5. package/dist/style.css +1 -1
  6. package/package.json +4 -3
  7. package/src/BlockNoteEditor.ts +100 -53
  8. package/src/BlockNoteExtensions.ts +24 -14
  9. package/src/api/blockManipulation/blockManipulation.test.ts +6 -3
  10. package/src/api/blockManipulation/blockManipulation.ts +7 -6
  11. package/src/api/formatConversions/formatConversions.test.ts +13 -8
  12. package/src/api/formatConversions/formatConversions.ts +15 -12
  13. package/src/api/nodeConversions/nodeConversions.test.ts +29 -10
  14. package/src/api/nodeConversions/nodeConversions.ts +33 -12
  15. package/src/api/nodeConversions/testUtil.ts +8 -4
  16. package/src/editor.module.css +0 -1
  17. package/src/extensions/Blocks/api/block.ts +229 -0
  18. package/src/extensions/Blocks/api/blockTypes.ts +158 -71
  19. package/src/extensions/Blocks/api/cursorPositionTypes.ts +5 -5
  20. package/src/extensions/Blocks/api/defaultBlocks.ts +44 -0
  21. package/src/extensions/Blocks/api/selectionTypes.ts +3 -3
  22. package/src/extensions/Blocks/api/serialization.ts +29 -0
  23. package/src/extensions/Blocks/index.ts +0 -8
  24. package/src/extensions/Blocks/nodes/Block.module.css +24 -12
  25. package/src/extensions/Blocks/nodes/BlockContainer.ts +8 -4
  26. package/src/extensions/Blocks/nodes/BlockContent/HeadingBlockContent/HeadingBlockContent.ts +4 -4
  27. package/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts +5 -5
  28. package/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts +100 -97
  29. package/src/extensions/Blocks/nodes/BlockContent/ParagraphBlockContent/ParagraphBlockContent.ts +4 -4
  30. package/src/extensions/DraggableBlocks/BlockSideMenuFactoryTypes.ts +11 -9
  31. package/src/extensions/DraggableBlocks/DraggableBlocksExtension.ts +6 -5
  32. package/src/extensions/DraggableBlocks/DraggableBlocksPlugin.ts +12 -11
  33. package/src/extensions/FormattingToolbar/FormattingToolbarExtension.ts +21 -16
  34. package/src/extensions/FormattingToolbar/FormattingToolbarFactoryTypes.ts +9 -5
  35. package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +30 -42
  36. package/src/extensions/Placeholder/PlaceholderExtension.ts +1 -0
  37. package/src/extensions/SlashMenu/BaseSlashMenuItem.ts +5 -2
  38. package/src/extensions/SlashMenu/SlashMenuExtension.ts +37 -33
  39. package/src/extensions/SlashMenu/defaultSlashMenuItems.tsx +14 -10
  40. package/src/extensions/SlashMenu/index.ts +2 -2
  41. package/src/index.ts +4 -0
  42. package/src/shared/plugins/suggestion/SuggestionPlugin.ts +29 -13
  43. package/types/src/BlockNoteEditor.d.ts +37 -23
  44. package/types/src/BlockNoteExtensions.d.ts +15 -8
  45. package/types/src/api/blockManipulation/blockManipulation.d.ts +4 -4
  46. package/types/src/api/formatConversions/formatConversions.d.ts +5 -5
  47. package/types/src/api/nodeConversions/nodeConversions.d.ts +3 -3
  48. package/types/src/api/nodeConversions/testUtil.d.ts +2 -2
  49. package/types/src/extensions/Blocks/api/block.d.ts +6 -5
  50. package/types/src/extensions/Blocks/api/blockTypes.d.ts +77 -33
  51. package/types/src/extensions/Blocks/api/cursorPositionTypes.d.ts +5 -5
  52. package/types/src/extensions/Blocks/api/selectionTypes.d.ts +3 -3
  53. package/types/src/extensions/Blocks/api/serialization.d.ts +2 -0
  54. package/types/src/extensions/Blocks/nodes/BlockContainer.d.ts +3 -3
  55. package/types/src/extensions/Blocks/nodes/BlockContent/HeadingBlockContent/HeadingBlockContent.d.ts +1 -2
  56. package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.d.ts +1 -2
  57. package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.d.ts +1 -2
  58. package/types/src/extensions/Blocks/nodes/BlockContent/ParagraphBlockContent/ParagraphBlockContent.d.ts +1 -2
  59. package/types/src/extensions/DraggableBlocks/BlockSideMenuFactoryTypes.d.ts +7 -7
  60. package/types/src/extensions/DraggableBlocks/DraggableBlocksExtension.d.ts +5 -4
  61. package/types/src/extensions/DraggableBlocks/DraggableBlocksPlugin.d.ts +11 -10
  62. package/types/src/extensions/FormattingToolbar/FormattingToolbarExtension.d.ts +6 -5
  63. package/types/src/extensions/FormattingToolbar/FormattingToolbarFactoryTypes.d.ts +4 -3
  64. package/types/src/extensions/FormattingToolbar/FormattingToolbarPlugin.d.ts +16 -19
  65. package/types/src/extensions/SlashMenu/BaseSlashMenuItem.d.ts +4 -3
  66. package/types/src/extensions/SlashMenu/SlashMenuExtension.d.ts +5 -4
  67. package/types/src/extensions/SlashMenu/defaultSlashMenuItems.d.ts +66 -1
  68. package/types/src/extensions/SlashMenu/index.d.ts +2 -2
  69. package/types/src/index.d.ts +4 -0
  70. package/types/src/shared/plugins/suggestion/SuggestionPlugin.d.ts +5 -4
@@ -1,117 +1,120 @@
1
- import { InputRule, mergeAttributes, Node } from "@tiptap/core";
2
- import styles from "../../../Block.module.css";
1
+ import { InputRule, mergeAttributes } from "@tiptap/core";
2
+ import { createTipTapBlock } from "../../../../api/block";
3
3
  import { handleEnter } from "../ListItemKeyboardShortcuts";
4
4
  import { NumberedListIndexingPlugin } from "./NumberedListIndexingPlugin";
5
+ import styles from "../../../Block.module.css";
5
6
 
6
- export const NumberedListItemBlockContent = Node.create({
7
- name: "numberedListItem",
8
- group: "blockContent",
9
- content: "inline*",
7
+ export const NumberedListItemBlockContent =
8
+ createTipTapBlock<"numberedListItem">({
9
+ name: "numberedListItem",
10
+ content: "inline*",
10
11
 
11
- addAttributes() {
12
- return {
13
- index: {
14
- default: null,
15
- parseHTML: (element) => element.getAttribute("data-index"),
16
- renderHTML: (attributes) => {
17
- return {
18
- "data-index": attributes.index,
19
- };
12
+ addAttributes() {
13
+ return {
14
+ index: {
15
+ default: null,
16
+ parseHTML: (element) => element.getAttribute("data-index"),
17
+ renderHTML: (attributes) => {
18
+ return {
19
+ "data-index": attributes.index,
20
+ };
21
+ },
20
22
  },
21
- },
22
- };
23
- },
23
+ };
24
+ },
24
25
 
25
- addInputRules() {
26
- return [
27
- // Creates an ordered list when starting with "1.".
28
- new InputRule({
29
- find: new RegExp(`^1\\.\\s$`),
30
- handler: ({ state, chain, range }) => {
31
- chain()
32
- .BNUpdateBlock(state.selection.from, {
33
- type: "numberedListItem",
34
- props: {},
35
- })
36
- // Removes the "1." characters used to set the list.
37
- .deleteRange({ from: range.from, to: range.to });
38
- },
39
- }),
40
- ];
41
- },
26
+ addInputRules() {
27
+ return [
28
+ // Creates an ordered list when starting with "1.".
29
+ new InputRule({
30
+ find: new RegExp(`^1\\.\\s$`),
31
+ handler: ({ state, chain, range }) => {
32
+ chain()
33
+ .BNUpdateBlock(state.selection.from, {
34
+ type: "numberedListItem",
35
+ props: {},
36
+ })
37
+ // Removes the "1." characters used to set the list.
38
+ .deleteRange({ from: range.from, to: range.to });
39
+ },
40
+ }),
41
+ ];
42
+ },
42
43
 
43
- addKeyboardShortcuts() {
44
- return {
45
- Enter: () => handleEnter(this.editor),
46
- };
47
- },
44
+ addKeyboardShortcuts() {
45
+ return {
46
+ Enter: () => handleEnter(this.editor),
47
+ };
48
+ },
48
49
 
49
- addProseMirrorPlugins() {
50
- return [NumberedListIndexingPlugin()];
51
- },
50
+ addProseMirrorPlugins() {
51
+ return [NumberedListIndexingPlugin()];
52
+ },
52
53
 
53
- parseHTML() {
54
- return [
55
- // Case for regular HTML list structure.
56
- // (e.g.: when pasting from other apps)
57
- {
58
- tag: "li",
59
- getAttrs: (element) => {
60
- if (typeof element === "string") {
61
- return false;
62
- }
54
+ parseHTML() {
55
+ return [
56
+ // Case for regular HTML list structure.
57
+ // (e.g.: when pasting from other apps)
58
+ {
59
+ tag: "li",
60
+ getAttrs: (element) => {
61
+ if (typeof element === "string") {
62
+ return false;
63
+ }
63
64
 
64
- const parent = element.parentElement;
65
+ const parent = element.parentElement;
65
66
 
66
- if (parent === null) {
67
- return false;
68
- }
67
+ if (parent === null) {
68
+ return false;
69
+ }
69
70
 
70
- if (parent.tagName === "OL") {
71
- return {};
72
- }
71
+ if (parent.tagName === "OL") {
72
+ return {};
73
+ }
73
74
 
74
- return false;
75
- },
76
- node: "numberedListItem",
77
- },
78
- // Case for BlockNote list structure.
79
- // (e.g.: when pasting from blocknote)
80
- {
81
- tag: "p",
82
- getAttrs: (element) => {
83
- if (typeof element === "string") {
84
75
  return false;
85
- }
76
+ },
77
+ node: "numberedListItem",
78
+ },
79
+ // Case for BlockNote list structure.
80
+ // (e.g.: when pasting from blocknote)
81
+ {
82
+ tag: "p",
83
+ getAttrs: (element) => {
84
+ if (typeof element === "string") {
85
+ return false;
86
+ }
86
87
 
87
- const parent = element.parentElement;
88
+ const parent = element.parentElement;
88
89
 
89
- if (parent === null) {
90
- return false;
91
- }
90
+ if (parent === null) {
91
+ return false;
92
+ }
92
93
 
93
- if (parent.getAttribute("data-content-type") === "numberedListItem") {
94
- return {};
95
- }
94
+ if (
95
+ parent.getAttribute("data-content-type") === "numberedListItem"
96
+ ) {
97
+ return {};
98
+ }
96
99
 
97
- return false;
100
+ return false;
101
+ },
102
+ priority: 300,
103
+ node: "numberedListItem",
98
104
  },
99
- priority: 300,
100
- node: "numberedListItem",
101
- },
102
- ];
103
- },
105
+ ];
106
+ },
104
107
 
105
- renderHTML({ HTMLAttributes }) {
106
- return [
107
- "div",
108
- mergeAttributes(HTMLAttributes, {
109
- class: styles.blockContent,
110
- "data-content-type": this.name,
111
- }),
112
- // we use a <p> tag, because for <li> tags we'd need to add a <ul> parent for around siblings to be semantically correct,
113
- // which would be quite cumbersome
114
- ["p", 0],
115
- ];
116
- },
117
- });
108
+ renderHTML({ HTMLAttributes }) {
109
+ return [
110
+ "div",
111
+ mergeAttributes(HTMLAttributes, {
112
+ class: styles.blockContent,
113
+ "data-content-type": this.name,
114
+ }),
115
+ // we use a <p> tag, because for <li> tags we'd need to add a <ul> parent for around siblings to be semantically correct,
116
+ // which would be quite cumbersome
117
+ ["p", { class: styles.inlineContent }, 0],
118
+ ];
119
+ },
120
+ });
@@ -1,9 +1,9 @@
1
- import { mergeAttributes, Node } from "@tiptap/core";
1
+ import { mergeAttributes } from "@tiptap/core";
2
+ import { createTipTapBlock } from "../../../api/block";
2
3
  import styles from "../../Block.module.css";
3
4
 
4
- export const ParagraphBlockContent = Node.create({
5
+ export const ParagraphBlockContent = createTipTapBlock<"paragraph">({
5
6
  name: "paragraph",
6
- group: "blockContent",
7
7
  content: "inline*",
8
8
 
9
9
  parseHTML() {
@@ -23,7 +23,7 @@ export const ParagraphBlockContent = Node.create({
23
23
  class: styles.blockContent,
24
24
  "data-content-type": this.name,
25
25
  }),
26
- ["p", 0],
26
+ ["p", { class: styles.inlineContent }, 0],
27
27
  ];
28
28
  },
29
29
  });
@@ -1,9 +1,9 @@
1
1
  import { EditorElement, ElementFactory } from "../../shared/EditorElement";
2
2
  import { BlockNoteEditor } from "../../BlockNoteEditor";
3
- import { Block } from "../Blocks/api/blockTypes";
3
+ import { Block, BlockSchema } from "../Blocks/api/blockTypes";
4
4
 
5
- export type BlockSideMenuStaticParams = {
6
- editor: BlockNoteEditor;
5
+ export type BlockSideMenuStaticParams<BSchema extends BlockSchema> = {
6
+ editor: BlockNoteEditor<BSchema>;
7
7
 
8
8
  addBlock: () => void;
9
9
 
@@ -14,14 +14,16 @@ export type BlockSideMenuStaticParams = {
14
14
  unfreezeMenu: () => void;
15
15
  };
16
16
 
17
- export type BlockSideMenuDynamicParams = {
18
- block: Block;
17
+ export type BlockSideMenuDynamicParams<BSchema extends BlockSchema> = {
18
+ block: Block<BSchema>;
19
19
 
20
20
  referenceRect: DOMRect;
21
21
  };
22
22
 
23
- export type BlockSideMenu = EditorElement<BlockSideMenuDynamicParams>;
24
- export type BlockSideMenuFactory = ElementFactory<
25
- BlockSideMenuStaticParams,
26
- BlockSideMenuDynamicParams
23
+ export type BlockSideMenu<BSchema extends BlockSchema> = EditorElement<
24
+ BlockSideMenuDynamicParams<BSchema>
25
+ >;
26
+ export type BlockSideMenuFactory<BSchema extends BlockSchema> = ElementFactory<
27
+ BlockSideMenuStaticParams<BSchema>,
28
+ BlockSideMenuDynamicParams<BSchema>
27
29
  >;
@@ -2,11 +2,12 @@ import { Editor, Extension } from "@tiptap/core";
2
2
  import { BlockSideMenuFactory } from "./BlockSideMenuFactoryTypes";
3
3
  import { createDraggableBlocksPlugin } from "./DraggableBlocksPlugin";
4
4
  import { BlockNoteEditor } from "../../BlockNoteEditor";
5
+ import { BlockSchema } from "../Blocks/api/blockTypes";
5
6
 
6
- export type DraggableBlocksOptions = {
7
+ export type DraggableBlocksOptions<BSchema extends BlockSchema> = {
7
8
  tiptapEditor: Editor;
8
- editor: BlockNoteEditor;
9
- blockSideMenuFactory: BlockSideMenuFactory;
9
+ editor: BlockNoteEditor<BSchema>;
10
+ blockSideMenuFactory: BlockSideMenuFactory<BSchema>;
10
11
  };
11
12
 
12
13
  /**
@@ -15,8 +16,8 @@ export type DraggableBlocksOptions = {
15
16
  *
16
17
  * code based on https://github.com/ueberdosis/tiptap/issues/323#issuecomment-506637799
17
18
  */
18
- export const DraggableBlocksExtension =
19
- Extension.create<DraggableBlocksOptions>({
19
+ export const createDraggableBlocksExtension = <BSchema extends BlockSchema>() =>
20
+ Extension.create<DraggableBlocksOptions<BSchema>>({
20
21
  name: "DraggableBlocksExtension",
21
22
  priority: 1000, // Need to be high, in order to hide menu when typing slash
22
23
  addProseMirrorPlugins() {
@@ -15,6 +15,7 @@ import {
15
15
  import { DraggableBlocksOptions } from "./DraggableBlocksExtension";
16
16
  import { MultipleNodeSelection } from "./MultipleNodeSelection";
17
17
  import { BlockNoteEditor } from "../../BlockNoteEditor";
18
+ import { BlockSchema } from "../Blocks/api/blockTypes";
18
19
 
19
20
  const serializeForClipboard = (pv as any).__serializeForClipboard;
20
21
  // code based on https://github.com/ueberdosis/tiptap/issues/323#issuecomment-506637799
@@ -223,15 +224,15 @@ function dragStart(e: DragEvent, view: EditorView) {
223
224
  }
224
225
  }
225
226
 
226
- export type BlockMenuViewProps = {
227
+ export type BlockMenuViewProps<BSchema extends BlockSchema> = {
227
228
  tiptapEditor: Editor;
228
- editor: BlockNoteEditor;
229
- blockMenuFactory: BlockSideMenuFactory;
229
+ editor: BlockNoteEditor<BSchema>;
230
+ blockMenuFactory: BlockSideMenuFactory<BSchema>;
230
231
  horizontalPosAnchoredAtRoot: boolean;
231
232
  };
232
233
 
233
- export class BlockMenuView {
234
- editor: BlockNoteEditor;
234
+ export class BlockMenuView<BSchema extends BlockSchema> {
235
+ editor: BlockNoteEditor<BSchema>;
235
236
  private ttEditor: Editor;
236
237
 
237
238
  // When true, the drag handle with be anchored at the same level as root elements
@@ -240,7 +241,7 @@ export class BlockMenuView {
240
241
 
241
242
  horizontalPosAnchor: number;
242
243
 
243
- blockMenu: BlockSideMenu;
244
+ blockMenu: BlockSideMenu<BSchema>;
244
245
 
245
246
  hoveredBlock: HTMLElement | undefined;
246
247
 
@@ -254,7 +255,7 @@ export class BlockMenuView {
254
255
  editor,
255
256
  blockMenuFactory,
256
257
  horizontalPosAnchoredAtRoot,
257
- }: BlockMenuViewProps) {
258
+ }: BlockMenuViewProps<BSchema>) {
258
259
  this.editor = editor;
259
260
  this.ttEditor = tiptapEditor;
260
261
  this.horizontalPosAnchoredAtRoot = horizontalPosAnchoredAtRoot;
@@ -497,7 +498,7 @@ export class BlockMenuView {
497
498
  );
498
499
  }
499
500
 
500
- getStaticParams(): BlockSideMenuStaticParams {
501
+ getStaticParams(): BlockSideMenuStaticParams<BSchema> {
501
502
  return {
502
503
  editor: this.editor,
503
504
  addBlock: () => this.addBlock(),
@@ -516,7 +517,7 @@ export class BlockMenuView {
516
517
  };
517
518
  }
518
519
 
519
- getDynamicParams(): BlockSideMenuDynamicParams {
520
+ getDynamicParams(): BlockSideMenuDynamicParams<BSchema> {
520
521
  const blockContent = this.hoveredBlock!.firstChild! as HTMLElement;
521
522
  const blockContentBoundingBox = blockContent.getBoundingClientRect();
522
523
 
@@ -534,8 +535,8 @@ export class BlockMenuView {
534
535
  }
535
536
  }
536
537
 
537
- export const createDraggableBlocksPlugin = (
538
- options: DraggableBlocksOptions
538
+ export const createDraggableBlocksPlugin = <BSchema extends BlockSchema>(
539
+ options: DraggableBlocksOptions<BSchema>
539
540
  ) => {
540
541
  return new Plugin({
541
542
  key: new PluginKey("DraggableBlocksPlugin"),
@@ -1,17 +1,22 @@
1
1
  import { Extension } from "@tiptap/core";
2
2
  import { PluginKey } from "prosemirror-state";
3
- import { BlockNoteEditor } from "../..";
3
+ import { BlockNoteEditor, BlockSchema } from "../..";
4
4
  import { FormattingToolbarFactory } from "./FormattingToolbarFactoryTypes";
5
5
  import { createFormattingToolbarPlugin } from "./FormattingToolbarPlugin";
6
6
 
7
+ export type FormattingToolbarOptions<BSchema extends BlockSchema> = {
8
+ formattingToolbarFactory: FormattingToolbarFactory<BSchema>;
9
+ editor: BlockNoteEditor<BSchema>;
10
+ };
11
+
7
12
  /**
8
13
  * The menu that is displayed when selecting a piece of text.
9
14
  */
10
- export const FormattingToolbarExtension = Extension.create<{
11
- formattingToolbarFactory: FormattingToolbarFactory;
12
- editor: BlockNoteEditor;
13
- }>({
14
- name: "FormattingToolbarExtension",
15
+ export const createFormattingToolbarExtension = <
16
+ BSchema extends BlockSchema
17
+ >() =>
18
+ Extension.create<FormattingToolbarOptions<BSchema>>({
19
+ name: "FormattingToolbarExtension",
15
20
 
16
21
  addProseMirrorPlugins() {
17
22
  if (!this.options.formattingToolbarFactory || !this.options.editor) {
@@ -20,13 +25,13 @@ export const FormattingToolbarExtension = Extension.create<{
20
25
  );
21
26
  }
22
27
 
23
- return [
24
- createFormattingToolbarPlugin({
25
- tiptapEditor: this.editor,
26
- editor: this.options.editor,
27
- formattingToolbarFactory: this.options.formattingToolbarFactory,
28
- pluginKey: new PluginKey("FormattingToolbarPlugin"),
29
- }),
30
- ];
31
- },
32
- });
28
+ return [
29
+ createFormattingToolbarPlugin({
30
+ tiptapEditor: this.editor,
31
+ editor: this.options.editor,
32
+ formattingToolbarFactory: this.options.formattingToolbarFactory,
33
+ pluginKey: new PluginKey("FormattingToolbarPlugin"),
34
+ }),
35
+ ];
36
+ },
37
+ });
@@ -1,16 +1,20 @@
1
1
  import { EditorElement, ElementFactory } from "../../shared/EditorElement";
2
2
  import { BlockNoteEditor } from "../../BlockNoteEditor";
3
+ import { BlockSchema } from "../Blocks/api/blockTypes";
3
4
 
4
- export type FormattingToolbarStaticParams = {
5
- editor: BlockNoteEditor;
5
+ export type FormattingToolbarStaticParams<BSchema extends BlockSchema> = {
6
+ editor: BlockNoteEditor<BSchema>;
6
7
  };
7
8
 
8
9
  export type FormattingToolbarDynamicParams = {
9
10
  referenceRect: DOMRect;
10
11
  };
11
12
 
12
- export type FormattingToolbar = EditorElement<FormattingToolbarDynamicParams>;
13
- export type FormattingToolbarFactory = ElementFactory<
14
- FormattingToolbarStaticParams,
13
+ export type FormattingToolbar = EditorElement<
15
14
  FormattingToolbarDynamicParams
16
15
  >;
16
+ export type FormattingToolbarFactory<BSchema extends BlockSchema> =
17
+ ElementFactory<
18
+ FormattingToolbarStaticParams<BSchema>,
19
+ FormattingToolbarDynamicParams
20
+ >;
@@ -6,7 +6,7 @@ import {
6
6
  } from "@tiptap/core";
7
7
  import { EditorState, Plugin, PluginKey } from "prosemirror-state";
8
8
  import { EditorView } from "prosemirror-view";
9
- import { BlockNoteEditor } from "../..";
9
+ import { BlockNoteEditor, BlockSchema } from "../..";
10
10
  import {
11
11
  FormattingToolbar,
12
12
  FormattingToolbarDynamicParams,
@@ -16,29 +16,20 @@ import {
16
16
 
17
17
  // Same as TipTap bubblemenu plugin, but with these changes:
18
18
  // https://github.com/ueberdosis/tiptap/pull/2596/files
19
- export interface FormattingToolbarPluginProps {
19
+ export interface FormattingToolbarPluginProps<BSchema extends BlockSchema> {
20
20
  pluginKey: PluginKey;
21
21
  tiptapEditor: Editor;
22
- editor: BlockNoteEditor;
23
- formattingToolbarFactory: FormattingToolbarFactory;
24
- shouldShow?:
25
- | ((props: {
26
- editor: BlockNoteEditor;
27
- view: EditorView;
28
- state: EditorState;
29
- oldState?: EditorState;
30
- from: number;
31
- to: number;
32
- }) => boolean)
33
- | null;
22
+ editor: BlockNoteEditor<BSchema>;
23
+ formattingToolbarFactory: FormattingToolbarFactory<BSchema>;
34
24
  }
35
25
 
36
- export type FormattingToolbarViewProps = FormattingToolbarPluginProps & {
37
- view: EditorView;
38
- };
26
+ export type FormattingToolbarViewProps<BSchema extends BlockSchema> =
27
+ FormattingToolbarPluginProps<BSchema> & {
28
+ view: EditorView;
29
+ };
39
30
 
40
- export class FormattingToolbarView {
41
- public editor: BlockNoteEditor;
31
+ export class FormattingToolbarView<BSchema extends BlockSchema> {
32
+ public editor: BlockNoteEditor<BSchema>;
42
33
  private ttEditor: Editor;
43
34
 
44
35
  public view: EditorView;
@@ -53,44 +44,43 @@ export class FormattingToolbarView {
53
44
 
54
45
  public prevWasEditable: boolean | null = null;
55
46
 
56
- public shouldShow: Exclude<FormattingToolbarPluginProps["shouldShow"], null> =
57
- ({ view, state, from, to }) => {
58
- const { doc, selection } = state;
59
- const { empty } = selection;
47
+ public shouldShow: (props: {
48
+ view: EditorView;
49
+ state: EditorState;
50
+ from: number;
51
+ to: number;
52
+ }) => boolean = ({ view, state, from, to }) => {
53
+ const { doc, selection } = state;
54
+ const { empty } = selection;
60
55
 
61
- // Sometime check for `empty` is not enough.
62
- // Doubleclick an empty paragraph returns a node size of 2.
63
- // So we check also for an empty text size.
64
- const isEmptyTextBlock =
65
- !doc.textBetween(from, to).length && isTextSelection(state.selection);
56
+ // Sometime check for `empty` is not enough.
57
+ // Doubleclick an empty paragraph returns a node size of 2.
58
+ // So we check also for an empty text size.
59
+ const isEmptyTextBlock =
60
+ !doc.textBetween(from, to).length && isTextSelection(state.selection);
66
61
 
67
- return !(!view.hasFocus() || empty || isEmptyTextBlock);
68
- };
62
+ return !(!view.hasFocus() || empty || isEmptyTextBlock);
63
+ };
69
64
 
70
65
  constructor({
71
66
  editor,
72
67
  tiptapEditor,
73
68
  formattingToolbarFactory,
74
69
  view,
75
- shouldShow,
76
- }: FormattingToolbarViewProps) {
70
+ }: FormattingToolbarViewProps<BSchema>) {
77
71
  this.editor = editor;
78
72
  this.ttEditor = tiptapEditor;
79
73
  this.view = view;
80
74
 
81
75
  this.formattingToolbar = formattingToolbarFactory(this.getStaticParams());
82
76
 
83
- if (shouldShow) {
84
- this.shouldShow = shouldShow;
85
- }
86
-
87
77
  this.view.dom.addEventListener("mousedown", this.viewMousedownHandler);
88
78
  this.view.dom.addEventListener("mouseup", this.viewMouseupHandler);
89
79
  this.view.dom.addEventListener("dragstart", this.dragstartHandler);
90
80
 
91
81
  this.ttEditor.on("focus", this.focusHandler);
92
82
  this.ttEditor.on("blur", this.blurHandler);
93
-
83
+
94
84
  document.addEventListener("scroll", this.scrollHandler);
95
85
  }
96
86
 
@@ -163,10 +153,8 @@ export class FormattingToolbarView {
163
153
  const to = Math.max(...ranges.map((range) => range.$to.pos));
164
154
 
165
155
  const shouldShow = this.shouldShow?.({
166
- editor: this.editor,
167
156
  view,
168
157
  state,
169
- oldState,
170
158
  from,
171
159
  to,
172
160
  });
@@ -250,7 +238,7 @@ export class FormattingToolbarView {
250
238
  return posToDOMRect(this.ttEditor.view, from, to);
251
239
  }
252
240
 
253
- getStaticParams(): FormattingToolbarStaticParams {
241
+ getStaticParams(): FormattingToolbarStaticParams<BSchema> {
254
242
  return {
255
243
  editor: this.editor,
256
244
  };
@@ -263,8 +251,8 @@ export class FormattingToolbarView {
263
251
  }
264
252
  }
265
253
 
266
- export const createFormattingToolbarPlugin = (
267
- options: FormattingToolbarPluginProps
254
+ export const createFormattingToolbarPlugin = <BSchema extends BlockSchema>(
255
+ options: FormattingToolbarPluginProps<BSchema>
268
256
  ) => {
269
257
  return new Plugin({
270
258
  key: new PluginKey("FormattingToolbarPlugin"),
@@ -72,6 +72,7 @@ export const Placeholder = Extension.create<PlaceholderOptions>({
72
72
  if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {
73
73
  const classes = [this.options.emptyNodeClass];
74
74
 
75
+ // TODO: Doesn't work?
75
76
  if (this.editor.isEmpty) {
76
77
  classes.push(this.options.emptyEditorClass);
77
78
  }
@@ -1,12 +1,15 @@
1
1
  import { SuggestionItem } from "../../shared/plugins/suggestion/SuggestionItem";
2
2
  import { BlockNoteEditor } from "../../BlockNoteEditor";
3
+ import { BlockSchema } from "../Blocks/api/blockTypes";
3
4
 
4
5
  /**
5
6
  * A class that defines a slash command (/<command>).
6
7
  *
7
8
  * (Not to be confused with ProseMirror commands nor TipTap commands.)
8
9
  */
9
- export class BaseSlashMenuItem extends SuggestionItem {
10
+ export class BaseSlashMenuItem<
11
+ BSchema extends BlockSchema
12
+ > extends SuggestionItem {
10
13
  /**
11
14
  * Constructs a new slash-command.
12
15
  *
@@ -16,7 +19,7 @@ export class BaseSlashMenuItem extends SuggestionItem {
16
19
  */
17
20
  constructor(
18
21
  public readonly name: string,
19
- public readonly execute: (editor: BlockNoteEditor) => void,
22
+ public readonly execute: (editor: BlockNoteEditor<BSchema>) => void,
20
23
  public readonly aliases: string[] = []
21
24
  ) {
22
25
  super(name, (query: string): boolean => {