@blocknote/core 0.8.5 → 0.9.2

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 (65) hide show
  1. package/dist/blocknote.js +705 -572
  2. package/dist/blocknote.js.map +1 -1
  3. package/dist/blocknote.umd.cjs +5 -4
  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 +13 -17
  8. package/src/BlockNoteExtensions.ts +42 -27
  9. package/src/api/blockManipulation/blockManipulation.test.ts +2 -2
  10. package/src/api/blockManipulation/blockManipulation.ts +1 -1
  11. package/src/api/formatConversions/formatConversions.test.ts +2 -2
  12. package/src/api/formatConversions/formatConversions.ts +47 -3
  13. package/src/api/nodeConversions/nodeConversions.test.ts +6 -6
  14. package/src/api/nodeConversions/nodeConversions.ts +6 -6
  15. package/src/editor.module.css +0 -11
  16. package/src/extensions/Blocks/PreviousBlockTypePlugin.ts +2 -2
  17. package/src/extensions/Blocks/api/block.ts +55 -22
  18. package/src/extensions/Blocks/api/blockTypes.ts +22 -3
  19. package/src/extensions/Blocks/helpers/getBlockInfoFromPos.ts +27 -5
  20. package/src/extensions/Blocks/index.ts +7 -12
  21. package/src/extensions/Blocks/nodes/Block.module.css +1 -1
  22. package/src/extensions/Blocks/nodes/BlockContainer.ts +20 -19
  23. package/src/extensions/Blocks/nodes/BlockContent/HeadingBlockContent/HeadingBlockContent.ts +20 -2
  24. package/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts +20 -2
  25. package/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts +20 -2
  26. package/src/extensions/Blocks/nodes/BlockContent/ParagraphBlockContent/ParagraphBlockContent.ts +29 -6
  27. package/src/extensions/Blocks/nodes/BlockGroup.ts +19 -11
  28. package/src/extensions/SideMenu/MultipleNodeSelection.ts +3 -3
  29. package/src/extensions/SideMenu/SideMenuPlugin.ts +9 -9
  30. package/src/extensions/UniqueID/UniqueID.ts +10 -9
  31. package/src/index.ts +1 -0
  32. package/src/shared/EventEmitter.ts +1 -0
  33. package/src/shared/plugins/suggestion/SuggestionPlugin.ts +6 -2
  34. package/src/shared/utils.ts +4 -0
  35. package/types/src/BlockNoteEditor.d.ts +4 -10
  36. package/types/src/BlockNoteExtensions.d.ts +2 -0
  37. package/types/src/extensions/Blocks/api/block.d.ts +6 -1
  38. package/types/src/extensions/Blocks/api/blockTypes.d.ts +15 -3
  39. package/types/src/extensions/Blocks/api/defaultBlocks.d.ts +36 -4
  40. package/types/src/extensions/Blocks/helpers/getBlockInfoFromPos.d.ts +9 -1
  41. package/types/src/extensions/Blocks/index.d.ts +4 -1
  42. package/types/src/extensions/Blocks/nodes/BlockContainer.d.ts +9 -4
  43. package/types/src/extensions/Blocks/nodes/BlockContent/HeadingBlockContent/HeadingBlockContent.d.ts +9 -1
  44. package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.d.ts +9 -1
  45. package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.d.ts +9 -1
  46. package/types/src/extensions/Blocks/nodes/BlockContent/ParagraphBlockContent/ParagraphBlockContent.d.ts +9 -1
  47. package/types/src/extensions/Blocks/nodes/BlockGroup.d.ts +9 -1
  48. package/types/src/extensions/Blocks/nodes/TableCell.d.ts +5 -0
  49. package/types/src/extensions/Blocks/nodes/TableRow.d.ts +5 -0
  50. package/types/src/extensions/SideMenu/MultipleNodeSelection.d.ts +1 -1
  51. package/types/src/index.d.ts +1 -0
  52. package/types/src/shared/utils.d.ts +1 -0
  53. package/src/node_modules/.vitest/results.json +0 -1
  54. package/types/src/EventEmitter.d.ts +0 -11
  55. package/types/src/extensions/DraggableBlocks/BlockSideMenuFactoryTypes.d.ts +0 -0
  56. package/types/src/extensions/DraggableBlocks/DraggableBlocksExtension.d.ts +0 -16
  57. package/types/src/extensions/DraggableBlocks/DraggableBlocksPlugin.d.ts +0 -55
  58. package/types/src/extensions/DraggableBlocks/MultipleNodeSelection.d.ts +0 -24
  59. package/types/src/extensions/FormattingToolbar/FormattingToolbarExtension.d.ts +0 -11
  60. package/types/src/extensions/FormattingToolbar/FormattingToolbarFactoryTypes.d.ts +0 -10
  61. package/types/src/extensions/HyperlinkToolbar/HyperlinkMark.d.ts +0 -8
  62. package/types/src/extensions/HyperlinkToolbar/HyperlinkToolbarFactoryTypes.d.ts +0 -0
  63. package/types/src/extensions/SlashMenu/SlashMenuExtension.d.ts +0 -13
  64. package/types/src/extensions/SlashMenu/index.d.ts +0 -3
  65. package/types/src/shared/plugins/suggestion/SuggestionsMenuFactoryTypes.d.ts +0 -12
@@ -1,16 +1,40 @@
1
1
  import { Node, NodeType } from "prosemirror-model";
2
2
 
3
- export type BlockInfo = {
3
+ export type BlockInfoWithoutPositions = {
4
4
  id: string;
5
5
  node: Node;
6
6
  contentNode: Node;
7
7
  contentType: NodeType;
8
8
  numChildBlocks: number;
9
+ };
10
+
11
+ export type BlockInfo = BlockInfoWithoutPositions & {
9
12
  startPos: number;
10
13
  endPos: number;
11
14
  depth: number;
12
15
  };
13
16
 
17
+ /**
18
+ * Helper function for `getBlockInfoFromPos`, returns information regarding
19
+ * provided blockContainer node.
20
+ * @param blockContainer The blockContainer node to retrieve info for.
21
+ */
22
+ export function getBlockInfo(blockContainer: Node): BlockInfoWithoutPositions {
23
+ const id = blockContainer.attrs["id"];
24
+ const contentNode = blockContainer.firstChild!;
25
+ const contentType = contentNode.type;
26
+ const numChildBlocks =
27
+ blockContainer.childCount === 2 ? blockContainer.lastChild!.childCount : 0;
28
+
29
+ return {
30
+ id,
31
+ node: blockContainer,
32
+ contentNode,
33
+ contentType,
34
+ numChildBlocks,
35
+ };
36
+ }
37
+
14
38
  /**
15
39
  * Retrieves information regarding the nearest blockContainer node in a
16
40
  * ProseMirror doc, relative to a position.
@@ -56,6 +80,7 @@ export function getBlockInfoFromPos(doc: Node, pos: number): BlockInfo {
56
80
  let node = $pos.node(maxDepth);
57
81
  let depth = maxDepth;
58
82
 
83
+ // eslint-disable-next-line no-constant-condition
59
84
  while (true) {
60
85
  if (depth < 0) {
61
86
  throw new Error(
@@ -71,10 +96,7 @@ export function getBlockInfoFromPos(doc: Node, pos: number): BlockInfo {
71
96
  node = $pos.node(depth);
72
97
  }
73
98
 
74
- const id = node.attrs["id"];
75
- const contentNode = node.firstChild!;
76
- const contentType = contentNode.type;
77
- const numChildBlocks = node.childCount === 2 ? node.lastChild!.childCount : 0;
99
+ const { id, contentNode, contentType, numChildBlocks } = getBlockInfo(node);
78
100
 
79
101
  const startPos = $pos.start(depth);
80
102
  const endPos = $pos.end(depth);
@@ -1,13 +1,8 @@
1
1
  import { Node } from "@tiptap/core";
2
- import { BlockContainer } from "./nodes/BlockContainer";
3
- import { BlockGroup } from "./nodes/BlockGroup";
4
-
5
- export const blocks: any[] = [
6
- BlockContainer,
7
- BlockGroup,
8
- Node.create({
9
- name: "doc",
10
- topNode: true,
11
- content: "blockGroup",
12
- }),
13
- ];
2
+ export { BlockContainer } from "./nodes/BlockContainer";
3
+ export { BlockGroup } from "./nodes/BlockGroup";
4
+ export const Doc = Node.create({
5
+ name: "doc",
6
+ topNode: true,
7
+ content: "blockGroup",
8
+ });
@@ -260,7 +260,7 @@ NESTED BLOCKS
260
260
 
261
261
  /* TODO: would be nicer if defined from code */
262
262
 
263
- .isEmpty.hasAnchor .inlineContent:before {
263
+ .blockContent.isEmpty.hasAnchor .inlineContent:before {
264
264
  content: "Enter text or type '/' for commands";
265
265
  }
266
266
 
@@ -6,16 +6,16 @@ import {
6
6
  inlineContentToNodes,
7
7
  } from "../../../api/nodeConversions/nodeConversions";
8
8
 
9
+ import {
10
+ BlockNoteDOMAttributes,
11
+ BlockSchema,
12
+ PartialBlock,
13
+ } from "../api/blockTypes";
9
14
  import { getBlockInfoFromPos } from "../helpers/getBlockInfoFromPos";
10
15
  import { PreviousBlockTypePlugin } from "../PreviousBlockTypePlugin";
11
16
  import styles from "./Block.module.css";
12
17
  import BlockAttributes from "./BlockAttributes";
13
- import { BlockSchema, PartialBlock } from "../api/blockTypes";
14
-
15
- // TODO
16
- export interface IBlock {
17
- HTMLAttributes: Record<string, any>;
18
- }
18
+ import { mergeCSSClasses } from "../../../shared/utils";
19
19
 
20
20
  declare module "@tiptap/core" {
21
21
  interface Commands<ReturnType> {
@@ -39,7 +39,9 @@ declare module "@tiptap/core" {
39
39
  /**
40
40
  * The main "Block node" documents consist of
41
41
  */
42
- export const BlockContainer = Node.create<IBlock>({
42
+ export const BlockContainer = Node.create<{
43
+ domAttributes?: BlockNoteDOMAttributes;
44
+ }>({
43
45
  name: "blockContainer",
44
46
  group: "blockContainer",
45
47
  // A block always contains content, and optionally a blockGroup which contains nested blocks
@@ -48,12 +50,6 @@ export const BlockContainer = Node.create<IBlock>({
48
50
  priority: 50,
49
51
  defining: true,
50
52
 
51
- addOptions() {
52
- return {
53
- HTMLAttributes: {},
54
- };
55
- },
56
-
57
53
  parseHTML() {
58
54
  return [
59
55
  {
@@ -64,7 +60,7 @@ export const BlockContainer = Node.create<IBlock>({
64
60
  }
65
61
 
66
62
  const attrs: Record<string, string> = {};
67
- for (let [nodeAttr, HTMLAttr] of Object.entries(BlockAttributes)) {
63
+ for (const [nodeAttr, HTMLAttr] of Object.entries(BlockAttributes)) {
68
64
  if (element.getAttribute(HTMLAttr)) {
69
65
  attrs[nodeAttr] = element.getAttribute(HTMLAttr)!;
70
66
  }
@@ -81,6 +77,8 @@ export const BlockContainer = Node.create<IBlock>({
81
77
  },
82
78
 
83
79
  renderHTML({ HTMLAttributes }) {
80
+ const domAttributes = this.options.domAttributes?.blockContainer || {};
81
+
84
82
  return [
85
83
  "div",
86
84
  mergeAttributes(HTMLAttributes, {
@@ -89,11 +87,14 @@ export const BlockContainer = Node.create<IBlock>({
89
87
  }),
90
88
  [
91
89
  "div",
92
- mergeAttributes(HTMLAttributes, {
93
- // TODO: maybe remove html attributes from inner block
94
- class: styles.block,
95
- "data-node-type": this.name,
96
- }),
90
+ mergeAttributes(
91
+ {
92
+ ...domAttributes,
93
+ class: mergeCSSClasses(styles.block, domAttributes.class),
94
+ "data-node-type": this.name,
95
+ },
96
+ HTMLAttributes
97
+ ),
97
98
  0,
98
99
  ],
99
100
  ];
@@ -1,6 +1,7 @@
1
1
  import { InputRule, mergeAttributes } from "@tiptap/core";
2
2
  import { createTipTapBlock } from "../../../api/block";
3
3
  import styles from "../../Block.module.css";
4
+ import { mergeCSSClasses } from "../../../../../shared/utils";
4
5
 
5
6
  export const HeadingBlockContent = createTipTapBlock<"heading">({
6
7
  name: "heading",
@@ -64,13 +65,30 @@ export const HeadingBlockContent = createTipTapBlock<"heading">({
64
65
  },
65
66
 
66
67
  renderHTML({ node, HTMLAttributes }) {
68
+ const blockContentDOMAttributes =
69
+ this.options.domAttributes?.blockContent || {};
70
+ const inlineContentDOMAttributes =
71
+ this.options.domAttributes?.inlineContent || {};
72
+
67
73
  return [
68
74
  "div",
69
75
  mergeAttributes(HTMLAttributes, {
70
- class: styles.blockContent,
76
+ class: mergeCSSClasses(
77
+ styles.blockContent,
78
+ blockContentDOMAttributes.class
79
+ ),
71
80
  "data-content-type": this.name,
72
81
  }),
73
- ["h" + node.attrs.level, { class: styles.inlineContent }, 0],
82
+ [
83
+ "h" + node.attrs.level,
84
+ {
85
+ class: mergeCSSClasses(
86
+ styles.inlineContent,
87
+ inlineContentDOMAttributes.class
88
+ ),
89
+ },
90
+ 0,
91
+ ],
74
92
  ];
75
93
  },
76
94
  });
@@ -2,6 +2,7 @@ import { InputRule, mergeAttributes } from "@tiptap/core";
2
2
  import { createTipTapBlock } from "../../../../api/block";
3
3
  import { handleEnter } from "../ListItemKeyboardShortcuts";
4
4
  import styles from "../../../Block.module.css";
5
+ import { mergeCSSClasses } from "../../../../../../shared/utils";
5
6
 
6
7
  export const BulletListItemBlockContent = createTipTapBlock<"bulletListItem">({
7
8
  name: "bulletListItem",
@@ -82,13 +83,30 @@ export const BulletListItemBlockContent = createTipTapBlock<"bulletListItem">({
82
83
  },
83
84
 
84
85
  renderHTML({ HTMLAttributes }) {
86
+ const blockContentDOMAttributes =
87
+ this.options.domAttributes?.blockContent || {};
88
+ const inlineContentDOMAttributes =
89
+ this.options.domAttributes?.inlineContent || {};
90
+
85
91
  return [
86
92
  "div",
87
93
  mergeAttributes(HTMLAttributes, {
88
- class: styles.blockContent,
94
+ class: mergeCSSClasses(
95
+ styles.blockContent,
96
+ blockContentDOMAttributes.class
97
+ ),
89
98
  "data-content-type": this.name,
90
99
  }),
91
- ["p", { class: styles.inlineContent }, 0],
100
+ [
101
+ "p",
102
+ {
103
+ class: mergeCSSClasses(
104
+ styles.inlineContent,
105
+ inlineContentDOMAttributes.class
106
+ ),
107
+ },
108
+ 0,
109
+ ],
92
110
  ];
93
111
  },
94
112
  });
@@ -3,6 +3,7 @@ import { createTipTapBlock } from "../../../../api/block";
3
3
  import { handleEnter } from "../ListItemKeyboardShortcuts";
4
4
  import { NumberedListIndexingPlugin } from "./NumberedListIndexingPlugin";
5
5
  import styles from "../../../Block.module.css";
6
+ import { mergeCSSClasses } from "../../../../../../shared/utils";
6
7
 
7
8
  export const NumberedListItemBlockContent =
8
9
  createTipTapBlock<"numberedListItem">({
@@ -106,15 +107,32 @@ export const NumberedListItemBlockContent =
106
107
  },
107
108
 
108
109
  renderHTML({ HTMLAttributes }) {
110
+ const blockContentDOMAttributes =
111
+ this.options.domAttributes?.blockContent || {};
112
+ const inlineContentDOMAttributes =
113
+ this.options.domAttributes?.inlineContent || {};
114
+
109
115
  return [
110
116
  "div",
111
117
  mergeAttributes(HTMLAttributes, {
112
- class: styles.blockContent,
118
+ class: mergeCSSClasses(
119
+ styles.blockContent,
120
+ blockContentDOMAttributes.class
121
+ ),
113
122
  "data-content-type": this.name,
114
123
  }),
115
124
  // 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
125
  // which would be quite cumbersome
117
- ["p", { class: styles.inlineContent }, 0],
126
+ [
127
+ "p",
128
+ {
129
+ class: mergeCSSClasses(
130
+ styles.inlineContent,
131
+ inlineContentDOMAttributes.class
132
+ ),
133
+ },
134
+ 0,
135
+ ],
118
136
  ];
119
137
  },
120
138
  });
@@ -1,8 +1,9 @@
1
1
  import { mergeAttributes } from "@tiptap/core";
2
2
  import { createTipTapBlock } from "../../../api/block";
3
3
  import styles from "../../Block.module.css";
4
+ import { mergeCSSClasses } from "../../../../../shared/utils";
4
5
 
5
- export const ParagraphBlockContent = createTipTapBlock<"paragraph">({
6
+ export const ParagraphBlockContent = createTipTapBlock({
6
7
  name: "paragraph",
7
8
  content: "inline*",
8
9
 
@@ -17,13 +18,35 @@ export const ParagraphBlockContent = createTipTapBlock<"paragraph">({
17
18
  },
18
19
 
19
20
  renderHTML({ HTMLAttributes }) {
21
+ const blockContentDOMAttributes =
22
+ this.options.domAttributes?.blockContent || {};
23
+ const inlineContentDOMAttributes =
24
+ this.options.domAttributes?.inlineContent || {};
25
+
20
26
  return [
21
27
  "div",
22
- mergeAttributes(HTMLAttributes, {
23
- class: styles.blockContent,
24
- "data-content-type": this.name,
25
- }),
26
- ["p", { class: styles.inlineContent }, 0],
28
+ mergeAttributes(
29
+ {
30
+ ...blockContentDOMAttributes,
31
+ class: mergeCSSClasses(
32
+ styles.blockContent,
33
+ blockContentDOMAttributes.class
34
+ ),
35
+ "data-content-type": this.name,
36
+ },
37
+ HTMLAttributes
38
+ ),
39
+ [
40
+ "p",
41
+ {
42
+ ...inlineContentDOMAttributes,
43
+ class: mergeCSSClasses(
44
+ styles.inlineContent,
45
+ inlineContentDOMAttributes.class
46
+ ),
47
+ },
48
+ 0,
49
+ ],
27
50
  ];
28
51
  },
29
52
  });
@@ -1,17 +1,15 @@
1
1
  import { mergeAttributes, Node } from "@tiptap/core";
2
2
  import styles from "./Block.module.css";
3
+ import { BlockNoteDOMAttributes } from "../api/blockTypes";
4
+ import { mergeCSSClasses } from "../../../shared/utils";
3
5
 
4
- export const BlockGroup = Node.create({
6
+ export const BlockGroup = Node.create<{
7
+ domAttributes?: BlockNoteDOMAttributes;
8
+ }>({
5
9
  name: "blockGroup",
6
10
  group: "blockGroup",
7
11
  content: "blockContainer+",
8
12
 
9
- addOptions() {
10
- return {
11
- HTMLAttributes: {},
12
- };
13
- },
14
-
15
13
  parseHTML() {
16
14
  return [
17
15
  {
@@ -33,12 +31,22 @@ export const BlockGroup = Node.create({
33
31
  },
34
32
 
35
33
  renderHTML({ HTMLAttributes }) {
34
+ const blockGroupDOMAttributes =
35
+ this.options.domAttributes?.blockGroup || {};
36
+
36
37
  return [
37
38
  "div",
38
- mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
39
- class: styles.blockGroup,
40
- "data-node-type": "blockGroup",
41
- }),
39
+ mergeAttributes(
40
+ {
41
+ ...blockGroupDOMAttributes,
42
+ class: mergeCSSClasses(
43
+ styles.blockGroup,
44
+ blockGroupDOMAttributes.class
45
+ ),
46
+ "data-node-type": "blockGroup",
47
+ },
48
+ HTMLAttributes
49
+ ),
42
50
  0,
43
51
  ];
44
52
  },
@@ -1,5 +1,5 @@
1
- import { Selection } from "prosemirror-state";
2
1
  import { Fragment, Node, ResolvedPos, Slice } from "prosemirror-model";
2
+ import { Selection } from "prosemirror-state";
3
3
  import { Mappable } from "prosemirror-transform";
4
4
 
5
5
  /**
@@ -64,8 +64,8 @@ export class MultipleNodeSelection extends Selection {
64
64
  }
65
65
 
66
66
  map(doc: Node, mapping: Mappable): Selection {
67
- let fromResult = mapping.mapResult(this.from);
68
- let toResult = mapping.mapResult(this.to);
67
+ const fromResult = mapping.mapResult(this.from);
68
+ const toResult = mapping.mapResult(this.to);
69
69
 
70
70
  if (toResult.deleted) {
71
71
  return Selection.near(doc.resolve(fromResult.pos));
@@ -32,7 +32,7 @@ function getDraggableBlockFromCoords(
32
32
  return undefined;
33
33
  }
34
34
 
35
- let pos = view.posAtCoords(coords);
35
+ const pos = view.posAtCoords(coords);
36
36
  if (!pos) {
37
37
  return undefined;
38
38
  }
@@ -61,12 +61,12 @@ function blockPositionFromCoords(
61
61
  coords: { left: number; top: number },
62
62
  view: EditorView
63
63
  ) {
64
- let block = getDraggableBlockFromCoords(coords, view);
64
+ const block = getDraggableBlockFromCoords(coords, view);
65
65
 
66
66
  if (block && block.node.nodeType === 1) {
67
67
  // TODO: this uses undocumented PM APIs? do we need this / let's add docs?
68
68
  const docView = (view as any).docView;
69
- let desc = docView.nearestDesc(block.node, true);
69
+ const desc = docView.nearestDesc(block.node, true);
70
70
  if (!desc || desc === docView) {
71
71
  return null;
72
72
  }
@@ -186,12 +186,12 @@ function dragStart(
186
186
 
187
187
  const editorBoundingBox = view.dom.getBoundingClientRect();
188
188
 
189
- let coords = {
189
+ const coords = {
190
190
  left: editorBoundingBox.left + editorBoundingBox.width / 2, // take middle of editor
191
191
  top: e.clientY,
192
192
  };
193
193
 
194
- let pos = blockPositionFromCoords(coords, view);
194
+ const pos = blockPositionFromCoords(coords, view);
195
195
  if (pos != null) {
196
196
  const selection = view.state.selection;
197
197
  const doc = view.state.doc;
@@ -215,8 +215,8 @@ function dragStart(
215
215
  setDragImage(view, pos);
216
216
  }
217
217
 
218
- let slice = view.state.selection.content();
219
- let { dom, text } = serializeForClipboard(view, slice);
218
+ const slice = view.state.selection.content();
219
+ const { dom, text } = serializeForClipboard(view, slice);
220
220
 
221
221
  e.dataTransfer.clearData();
222
222
  e.dataTransfer.setData("text/html", dom.innerHTML);
@@ -288,7 +288,7 @@ export class SideMenuView<BSchema extends BlockSchema> implements PluginView {
288
288
  return;
289
289
  }
290
290
 
291
- let pos = this.pmView.posAtCoords({
291
+ const pos = this.pmView.posAtCoords({
292
292
  left: event.clientX,
293
293
  top: event.clientY,
294
294
  });
@@ -319,7 +319,7 @@ export class SideMenuView<BSchema extends BlockSchema> implements PluginView {
319
319
  if ((event as any).synthetic || !this.isDragging) {
320
320
  return;
321
321
  }
322
- let pos = this.pmView.posAtCoords({
322
+ const pos = this.pmView.posAtCoords({
323
323
  left: event.clientX,
324
324
  top: event.clientY,
325
325
  });
@@ -52,14 +52,15 @@ const UniqueID = Extension.create({
52
52
  types: [],
53
53
  generateID: () => {
54
54
  // Use mock ID if tests are running.
55
- if ((window as any).__TEST_OPTIONS) {
56
- if ((window as any).__TEST_OPTIONS.mockID === undefined) {
57
- (window as any).__TEST_OPTIONS.mockID = 0;
55
+ if (typeof window !== "undefined" && (window as any).__TEST_OPTIONS) {
56
+ const testOptions = (window as any).__TEST_OPTIONS;
57
+ if (testOptions.mockID === undefined) {
58
+ testOptions.mockID = 0;
58
59
  } else {
59
- (window as any).__TEST_OPTIONS.mockID++;
60
+ testOptions.mockID++;
60
61
  }
61
62
 
62
- return (window as any).__TEST_OPTIONS.mockID.toString() as string;
63
+ return testOptions.mockID.toString() as string;
63
64
  }
64
65
 
65
66
  return v4();
@@ -129,7 +130,7 @@ const UniqueID = Extension.create({
129
130
  const filterTransactions =
130
131
  this.options.filterTransaction &&
131
132
  transactions.some((tr) => {
132
- var _a, _b;
133
+ let _a, _b;
133
134
  return !((_b = (_a = this.options).filterTransaction) === null ||
134
135
  _b === void 0
135
136
  ? void 0
@@ -161,7 +162,7 @@ const UniqueID = Extension.create({
161
162
  .filter((id) => id !== null);
162
163
  const duplicatedNewIds = findDuplicates(newIds);
163
164
  newNodes.forEach(({ node, pos }) => {
164
- var _a;
165
+ let _a;
165
166
  // instead of checking `node.attrs[attributeName]` directly
166
167
  // we look at the current state of the node within `tr.doc`.
167
168
  // this helps to prevent adding new ids to the same node
@@ -196,7 +197,7 @@ const UniqueID = Extension.create({
196
197
  // we register a global drag handler to track the current drag source element
197
198
  view(view) {
198
199
  const handleDragstart = (event: any) => {
199
- var _a;
200
+ let _a;
200
201
  dragSourceElement = (
201
202
  (_a = view.dom.parentElement) === null || _a === void 0
202
203
  ? void 0
@@ -219,7 +220,7 @@ const UniqueID = Extension.create({
219
220
  // only create new ids for dropped content while holding `alt`
220
221
  // or content is dragged from another editor
221
222
  drop: (view, event: any) => {
222
- var _a;
223
+ let _a;
223
224
  if (
224
225
  dragSourceElement !== view.dom.parentElement ||
225
226
  ((_a = event.dataTransfer) === null || _a === void 0
package/src/index.ts CHANGED
@@ -15,3 +15,4 @@ export { getDefaultSlashMenuItems } from "./extensions/SlashMenu/defaultSlashMen
15
15
  export * from "./shared/BaseUiElementTypes";
16
16
  export type { SuggestionItem } from "./shared/plugins/suggestion/SuggestionItem";
17
17
  export * from "./shared/plugins/suggestion/SuggestionPlugin";
18
+ export * from "./shared/utils";
@@ -11,6 +11,7 @@ type CallbackFunction<
11
11
  > = (...props: CallbackType<T, EventName>) => any;
12
12
 
13
13
  export class EventEmitter<T extends Record<string, any>> {
14
+ // eslint-disable-next-line @typescript-eslint/ban-types
14
15
  private callbacks: { [key: string]: Function[] } = {};
15
16
 
16
17
  public on<EventName extends StringKeyOf<T>>(
@@ -28,7 +28,9 @@ class SuggestionsMenuView<
28
28
  private readonly pluginKey: PluginKey,
29
29
  updateSuggestionsMenu: (
30
30
  suggestionsMenuState: SuggestionsMenuState<T>
31
- ) => void = () => {}
31
+ ) => void = () => {
32
+ // noop
33
+ }
32
34
  ) {
33
35
  this.pluginState = getDefaultPluginState<T>();
34
36
 
@@ -158,7 +160,9 @@ export const setupSuggestionsMenu = <
158
160
  onSelectItem: (props: {
159
161
  item: T;
160
162
  editor: BlockNoteEditor<BSchema>;
161
- }) => void = () => {}
163
+ }) => void = () => {
164
+ // noop
165
+ }
162
166
  ) => {
163
167
  // Assertions
164
168
  if (defaultTriggerCharacter.length !== 1) {
@@ -11,6 +11,10 @@ export function formatKeyboardShortcut(shortcut: string) {
11
11
  }
12
12
  }
13
13
 
14
+ export function mergeCSSClasses(...classes: string[]) {
15
+ return classes.filter((c) => c).join(" ");
16
+ }
17
+
14
18
  export class UnreachableCaseError extends Error {
15
19
  constructor(val: never) {
16
20
  super(`Unreachable case: ${val}`);
@@ -1,7 +1,7 @@
1
1
  import { Node } from "prosemirror-model";
2
2
  import { Editor as TiptapEditor } from "@tiptap/core/dist/packages/core/src/Editor";
3
3
  import * as Y from "yjs";
4
- import { Block, BlockIdentifier, BlockSchema, PartialBlock } from "./extensions/Blocks/api/blockTypes";
4
+ import { Block, BlockIdentifier, BlockNoteDOMAttributes, BlockSchema, PartialBlock } from "./extensions/Blocks/api/blockTypes";
5
5
  import { TextCursorPosition } from "./extensions/Blocks/api/cursorPositionTypes";
6
6
  import { DefaultBlockSchema } from "./extensions/Blocks/api/defaultBlocks";
7
7
  import { Styles } from "./extensions/Blocks/api/inlineContentTypes";
@@ -27,11 +27,11 @@ export type BlockNoteEditorOptions<BSchema extends BlockSchema> = {
27
27
  */
28
28
  parentElement: HTMLElement;
29
29
  /**
30
- * An object containing attributes that should be added to the editor's HTML element.
30
+ * An object containing attributes that should be added to HTML elements of the editor.
31
31
  *
32
- * @example { class: "my-editor-class" }
32
+ * @example { editor: { class: "my-editor-class" } }
33
33
  */
34
- editorDOMAttributes: Record<string, string>;
34
+ domAttributes: Partial<BlockNoteDOMAttributes>;
35
35
  /**
36
36
  * A callback function that runs when the editor is ready to be used.
37
37
  */
@@ -58,12 +58,6 @@ export type BlockNoteEditorOptions<BSchema extends BlockSchema> = {
58
58
  * @default true
59
59
  */
60
60
  defaultStyles: boolean;
61
- /**
62
- * Whether to use the light or dark theme.
63
- *
64
- * @default "light"
65
- */
66
- theme: "light" | "dark";
67
61
  /**
68
62
  * A list of block types that should be available in the editor.
69
63
  */
@@ -1,11 +1,13 @@
1
1
  import { Extensions } from "@tiptap/core";
2
2
  import { BlockNoteEditor } from "./BlockNoteEditor";
3
3
  import * as Y from "yjs";
4
+ import { BlockNoteDOMAttributes } from "./extensions/Blocks/api/blockTypes";
4
5
  /**
5
6
  * Get all the Tiptap extensions BlockNote is configured with by default
6
7
  */
7
8
  export declare const getBlockNoteExtensions: <BSchema extends Record<string, import("./extensions/Blocks/api/blockTypes").BlockSpec<string, import("./extensions/Blocks/api/blockTypes").PropSchema>>>(opts: {
8
9
  editor: BlockNoteEditor<BSchema>;
10
+ domAttributes: Partial<BlockNoteDOMAttributes>;
9
11
  blockSchema: BSchema;
10
12
  collaboration?: {
11
13
  fragment: Y.XmlFragment;
@@ -1,4 +1,5 @@
1
1
  import { Attribute } from "@tiptap/core";
2
+ import { BlockNoteDOMAttributes } from "../../..";
2
3
  import { BlockConfig, BlockSchema, BlockSpec, PropSchema, TipTapNode, TipTapNodeConfig } from "./blockTypes";
3
4
  export declare function camelToDataKebab(str: string): string;
4
5
  export declare function propsToAttributes<BType extends string, PSchema extends PropSchema, ContainsInlineContent extends boolean, BSchema extends BlockSchema>(blockConfig: Omit<BlockConfig<BType, PSchema, ContainsInlineContent, BSchema>, "render">): Record<string, Attribute>;
@@ -13,4 +14,8 @@ export declare function render<BType extends string, PSchema extends PropSchema,
13
14
  contentDOM?: undefined;
14
15
  };
15
16
  export declare function createBlockSpec<BType extends string, PSchema extends PropSchema, ContainsInlineContent extends boolean, BSchema extends BlockSchema>(blockConfig: BlockConfig<BType, PSchema, ContainsInlineContent, BSchema>): BlockSpec<BType, PSchema>;
16
- export declare function createTipTapBlock<Type extends string>(config: TipTapNodeConfig<Type>): TipTapNode<Type>;
17
+ export declare function createTipTapBlock<Type extends string, Options extends {
18
+ domAttributes?: BlockNoteDOMAttributes;
19
+ } = {
20
+ domAttributes?: BlockNoteDOMAttributes;
21
+ }, Storage = any>(config: TipTapNodeConfig<Type, Options, Storage>): TipTapNode<Type, Options, Storage>;