@blocknote/core 0.11.2 → 0.12.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 (128) hide show
  1. package/README.md +13 -17
  2. package/dist/blocknote.js +1600 -1403
  3. package/dist/blocknote.js.map +1 -1
  4. package/dist/blocknote.umd.cjs +6 -6
  5. package/dist/blocknote.umd.cjs.map +1 -1
  6. package/dist/style.css +1 -1
  7. package/dist/webpack-stats.json +1 -1
  8. package/package.json +7 -3
  9. package/src/api/blockManipulation/blockManipulation.test.ts +19 -15
  10. package/src/api/blockManipulation/blockManipulation.ts +107 -17
  11. package/src/api/exporters/html/externalHTMLExporter.ts +3 -7
  12. package/src/api/exporters/html/htmlConversion.test.ts +6 -3
  13. package/src/api/exporters/html/internalHTMLSerializer.ts +3 -7
  14. package/src/api/exporters/html/util/sharedHTMLConversion.ts +3 -3
  15. package/src/api/exporters/markdown/markdownExporter.test.ts +7 -3
  16. package/src/api/exporters/markdown/markdownExporter.ts +2 -6
  17. package/src/api/nodeConversions/nodeConversions.test.ts +14 -7
  18. package/src/api/nodeConversions/nodeConversions.ts +1 -2
  19. package/src/api/parsers/html/parseHTML.test.ts +5 -1
  20. package/src/api/parsers/html/parseHTML.ts +2 -6
  21. package/src/api/parsers/html/util/nestedLists.ts +11 -1
  22. package/src/api/parsers/markdown/parseMarkdown.test.ts +3 -0
  23. package/src/api/parsers/markdown/parseMarkdown.ts +2 -6
  24. package/src/api/testUtil/cases/customBlocks.ts +18 -16
  25. package/src/api/testUtil/cases/customInlineContent.ts +12 -13
  26. package/src/api/testUtil/cases/customStyles.ts +12 -10
  27. package/src/api/testUtil/index.ts +4 -2
  28. package/src/api/testUtil/partialBlockTestUtil.ts +2 -6
  29. package/src/blocks/ImageBlockContent/ImageBlockContent.ts +1 -2
  30. package/src/blocks/ImageBlockContent/uploadToTmpFilesDotOrg_DEV_ONLY.ts +8 -1
  31. package/src/blocks/defaultBlockHelpers.ts +3 -3
  32. package/src/blocks/defaultBlockTypeGuards.ts +84 -0
  33. package/src/blocks/defaultBlocks.ts +29 -3
  34. package/src/editor/Block.css +2 -31
  35. package/src/editor/BlockNoteEditor.ts +218 -262
  36. package/src/editor/BlockNoteExtensions.ts +5 -2
  37. package/src/editor/BlockNoteSchema.ts +98 -0
  38. package/src/editor/BlockNoteTipTapEditor.ts +162 -0
  39. package/src/editor/cursorPositionTypes.ts +2 -6
  40. package/src/editor/editor.css +0 -1
  41. package/src/editor/selectionTypes.ts +2 -6
  42. package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +22 -29
  43. package/src/extensions/HyperlinkToolbar/HyperlinkToolbarPlugin.ts +26 -27
  44. package/src/extensions/ImageToolbar/ImageToolbarPlugin.ts +45 -51
  45. package/src/extensions/Placeholder/PlaceholderExtension.ts +81 -88
  46. package/src/extensions/SideMenu/SideMenuPlugin.ts +55 -56
  47. package/src/extensions/SuggestionMenu/DefaultSuggestionItem.ts +8 -0
  48. package/src/extensions/SuggestionMenu/SuggestionPlugin.ts +353 -0
  49. package/src/extensions/{SlashMenu/defaultSlashMenuItems.ts → SuggestionMenu/getDefaultSlashMenuItems.ts} +119 -89
  50. package/src/extensions/TableHandles/TableHandlesPlugin.ts +62 -45
  51. package/src/extensions-shared/UiElementPosition.ts +4 -0
  52. package/src/index.ts +6 -6
  53. package/src/pm-nodes/BlockContainer.ts +5 -5
  54. package/src/schema/blocks/types.ts +15 -15
  55. package/src/schema/inlineContent/createSpec.ts +2 -2
  56. package/src/schema/inlineContent/types.ts +1 -1
  57. package/src/util/browser.ts +6 -4
  58. package/src/util/typescript.ts +7 -4
  59. package/types/src/api/blockManipulation/blockManipulation.d.ts +6 -1
  60. package/types/src/api/exporters/html/externalHTMLExporter.d.ts +2 -1
  61. package/types/src/api/exporters/html/internalHTMLSerializer.d.ts +2 -1
  62. package/types/src/api/exporters/markdown/markdownExporter.d.ts +2 -1
  63. package/types/src/api/nodeConversions/nodeConversions.d.ts +2 -1
  64. package/types/src/api/parsers/html/parseHTML.d.ts +2 -1
  65. package/types/src/api/parsers/markdown/parseMarkdown.d.ts +2 -1
  66. package/types/src/api/testUtil/cases/customBlocks.d.ts +72 -13
  67. package/types/src/api/testUtil/cases/customInlineContent.d.ts +281 -6
  68. package/types/src/api/testUtil/cases/customStyles.d.ts +247 -13
  69. package/types/src/api/testUtil/index.d.ts +4 -2
  70. package/types/src/api/testUtil/partialBlockTestUtil.d.ts +2 -1
  71. package/types/src/blocks/ImageBlockContent/uploadToTmpFilesDotOrg_DEV_ONLY.d.ts +6 -1
  72. package/types/src/blocks/defaultBlockHelpers.d.ts +2 -2
  73. package/types/src/blocks/defaultBlockTypeGuards.d.ts +24 -0
  74. package/types/src/blocks/defaultBlocks.d.ts +21 -15
  75. package/types/src/editor/BlockNoteEditor.d.ts +48 -53
  76. package/types/src/editor/BlockNoteExtensions.d.ts +1 -0
  77. package/types/src/editor/BlockNoteSchema.d.ts +34 -0
  78. package/types/src/editor/BlockNoteTipTapEditor.d.ts +28 -0
  79. package/types/src/editor/cursorPositionTypes.d.ts +2 -1
  80. package/types/src/editor/selectionTypes.d.ts +2 -1
  81. package/types/src/extensions/FormattingToolbar/FormattingToolbarPlugin.d.ts +5 -6
  82. package/types/src/extensions/HyperlinkToolbar/HyperlinkToolbarPlugin.d.ts +2 -2
  83. package/types/src/extensions/ImageToolbar/ImageToolbarPlugin.d.ts +15 -14
  84. package/types/src/extensions/Placeholder/PlaceholderExtension.d.ts +2 -15
  85. package/types/src/extensions/SideMenu/SideMenuPlugin.d.ts +8 -7
  86. package/types/src/extensions/SuggestionMenu/DefaultSuggestionItem.d.ts +8 -0
  87. package/types/src/extensions/SuggestionMenu/SuggestionPlugin.d.ts +31 -0
  88. package/types/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.d.ts +10 -0
  89. package/types/src/extensions/TableHandles/TableHandlesPlugin.d.ts +7 -7
  90. package/types/src/extensions-shared/UiElementPosition.d.ts +4 -0
  91. package/types/src/index.d.ts +6 -6
  92. package/types/src/pm-nodes/BlockContainer.d.ts +3 -2
  93. package/types/src/pm-nodes/BlockGroup.d.ts +1 -1
  94. package/types/src/schema/blocks/types.d.ts +15 -15
  95. package/types/src/schema/inlineContent/types.d.ts +1 -1
  96. package/types/src/util/browser.d.ts +1 -0
  97. package/types/src/util/typescript.d.ts +1 -0
  98. package/src/extensions/SlashMenu/BaseSlashMenuItem.ts +0 -12
  99. package/src/extensions/SlashMenu/SlashMenuPlugin.ts +0 -53
  100. package/src/extensions-shared/BaseUiElementTypes.ts +0 -8
  101. package/src/extensions-shared/README.md +0 -3
  102. package/src/extensions-shared/suggestion/SuggestionItem.ts +0 -3
  103. package/src/extensions-shared/suggestion/SuggestionPlugin.ts +0 -448
  104. package/types/src/extensions/SlashMenu/BaseSlashMenuItem.d.ts +0 -7
  105. package/types/src/extensions/SlashMenu/SlashMenuPlugin.d.ts +0 -13
  106. package/types/src/extensions/SlashMenu/defaultSlashMenuItems.d.ts +0 -3
  107. package/types/src/extensions-shared/BaseUiElementTypes.d.ts +0 -7
  108. package/types/src/extensions-shared/suggestion/SuggestionItem.d.ts +0 -3
  109. package/types/src/extensions-shared/suggestion/SuggestionPlugin.d.ts +0 -36
  110. /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-100.woff +0 -0
  111. /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-100.woff2 +0 -0
  112. /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-200.woff +0 -0
  113. /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-200.woff2 +0 -0
  114. /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-300.woff +0 -0
  115. /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-300.woff2 +0 -0
  116. /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-500.woff +0 -0
  117. /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-500.woff2 +0 -0
  118. /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-600.woff +0 -0
  119. /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-600.woff2 +0 -0
  120. /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-700.woff +0 -0
  121. /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-700.woff2 +0 -0
  122. /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-800.woff +0 -0
  123. /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-800.woff2 +0 -0
  124. /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-900.woff +0 -0
  125. /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-900.woff2 +0 -0
  126. /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-regular.woff +0 -0
  127. /package/src/{assets → fonts}/inter-v12-latin/inter-v12-latin-regular.woff2 +0 -0
  128. /package/src/{assets/fonts-inter.css → fonts/inter.css} +0 -0
@@ -39,6 +39,7 @@ export const getBlockNoteExtensions = <
39
39
  S extends StyleSchema
40
40
  >(opts: {
41
41
  editor: BlockNoteEditor<BSchema, I, S>;
42
+ placeholders?: Record<string | "default", string>;
42
43
  domAttributes: Partial<BlockNoteDOMAttributes>;
43
44
  blockSchema: BSchema;
44
45
  blockSpecs: BlockSpecs;
@@ -66,8 +67,10 @@ export const getBlockNoteExtensions = <
66
67
 
67
68
  // DropCursor,
68
69
  Placeholder.configure({
69
- includeChildren: true,
70
- showOnlyCurrent: false,
70
+ // TODO: This shorthand is kind of ugly
71
+ ...(opts.placeholders !== undefined
72
+ ? { placeholders: opts.placeholders }
73
+ : {}),
71
74
  }),
72
75
  UniqueID.configure({
73
76
  types: ["blockContainer"],
@@ -0,0 +1,98 @@
1
+ import {
2
+ defaultBlockSpecs,
3
+ defaultInlineContentSpecs,
4
+ defaultStyleSpecs,
5
+ } from "../blocks/defaultBlocks";
6
+ import {
7
+ BlockSchema,
8
+ BlockSchemaFromSpecs,
9
+ BlockSpecs,
10
+ InlineContentSchema,
11
+ InlineContentSchemaFromSpecs,
12
+ InlineContentSpecs,
13
+ StyleSchema,
14
+ StyleSchemaFromSpecs,
15
+ StyleSpecs,
16
+ getBlockSchemaFromSpecs,
17
+ getInlineContentSchemaFromSpecs,
18
+ getStyleSchemaFromSpecs,
19
+ } from "../schema";
20
+ import type {
21
+ BlockNoDefaults,
22
+ PartialBlockNoDefaults,
23
+ } from "../schema/blocks/types";
24
+ import type { BlockNoteEditor } from "./BlockNoteEditor";
25
+
26
+ export class BlockNoteSchema<
27
+ BSchema extends BlockSchema,
28
+ ISchema extends InlineContentSchema,
29
+ SSchema extends StyleSchema
30
+ > {
31
+ public readonly blockSpecs: BlockSpecs;
32
+ public readonly inlineContentSpecs: InlineContentSpecs;
33
+ public readonly styleSpecs: StyleSpecs;
34
+
35
+ public readonly blockSchema: BSchema;
36
+ public readonly inlineContentSchema: ISchema;
37
+ public readonly styleSchema: SSchema;
38
+
39
+ // Helper so that you can use typeof schema.BlockNoteEditor
40
+ public readonly BlockNoteEditor: BlockNoteEditor<BSchema, ISchema, SSchema> =
41
+ "only for types" as any;
42
+
43
+ public readonly Block: BlockNoDefaults<BSchema, ISchema, SSchema> =
44
+ "only for types" as any;
45
+
46
+ public readonly PartialBlock: PartialBlockNoDefaults<
47
+ BSchema,
48
+ ISchema,
49
+ SSchema
50
+ > = "only for types" as any;
51
+
52
+ public static create<
53
+ BSpecs extends BlockSpecs = typeof defaultBlockSpecs,
54
+ ISpecs extends InlineContentSpecs = typeof defaultInlineContentSpecs,
55
+ SSpecs extends StyleSpecs = typeof defaultStyleSpecs
56
+ >(options?: {
57
+ /**
58
+ * A list of custom block types that should be available in the editor.
59
+ */
60
+ blockSpecs?: BSpecs;
61
+ /**
62
+ * A list of custom InlineContent types that should be available in the editor.
63
+ */
64
+ inlineContentSpecs?: ISpecs;
65
+ /**
66
+ * A list of custom Styles that should be available in the editor.
67
+ */
68
+ styleSpecs?: SSpecs;
69
+ }) {
70
+ return new BlockNoteSchema<
71
+ BlockSchemaFromSpecs<BSpecs>,
72
+ InlineContentSchemaFromSpecs<ISpecs>,
73
+ StyleSchemaFromSpecs<SSpecs>
74
+ >(options);
75
+ // as BlockNoteSchema<
76
+ // BlockSchemaFromSpecs<BSpecs>,
77
+ // InlineContentSchemaFromSpecs<ISpecs>,
78
+ // StyleSchemaFromSpecs<SSpecs>
79
+ // >;
80
+ }
81
+
82
+ constructor(opts?: {
83
+ blockSpecs?: BlockSpecs;
84
+ inlineContentSpecs?: InlineContentSpecs;
85
+ styleSpecs?: StyleSpecs;
86
+ }) {
87
+ this.blockSpecs = opts?.blockSpecs || defaultBlockSpecs;
88
+ this.inlineContentSpecs =
89
+ opts?.inlineContentSpecs || defaultInlineContentSpecs;
90
+ this.styleSpecs = opts?.styleSpecs || defaultStyleSpecs;
91
+
92
+ this.blockSchema = getBlockSchemaFromSpecs(this.blockSpecs) as any;
93
+ this.inlineContentSchema = getInlineContentSchemaFromSpecs(
94
+ this.inlineContentSpecs
95
+ ) as any;
96
+ this.styleSchema = getStyleSchemaFromSpecs(this.styleSpecs) as any;
97
+ }
98
+ }
@@ -0,0 +1,162 @@
1
+ import { EditorOptions, createDocument } from "@tiptap/core";
2
+ // import "./blocknote.css";
3
+ import { Editor as TiptapEditor } from "@tiptap/core";
4
+ import { Node } from "@tiptap/pm/model";
5
+ import { EditorView } from "@tiptap/pm/view";
6
+ import { EditorState } from "prosemirror-state";
7
+
8
+ import { blockToNode } from "../api/nodeConversions/nodeConversions";
9
+ import { PartialBlock } from "../blocks/defaultBlocks";
10
+ import { StyleSchema } from "../schema";
11
+
12
+ export type BlockNoteTipTapEditorOptions = Partial<
13
+ Omit<EditorOptions, "content">
14
+ > & {
15
+ content: PartialBlock<any, any, any>[];
16
+ };
17
+
18
+ /**
19
+ * Custom Editor class that extends TiptapEditor and separates
20
+ * the creation of the view from the constructor.
21
+ */
22
+ // @ts-ignore
23
+ export class BlockNoteTipTapEditor extends TiptapEditor {
24
+ private _state: EditorState;
25
+
26
+ constructor(options: BlockNoteTipTapEditorOptions, styleSchema: StyleSchema) {
27
+ // possible fix for next.js server side rendering
28
+ // const d = globalThis.document;
29
+ // const w = globalThis.window;
30
+ // if (!globalThis.document) {
31
+ // globalThis.document = {
32
+ // createElement: () => {},
33
+ // };
34
+ // }
35
+ // if (!globalThis.window) {
36
+ // globalThis.window = {
37
+ // setTimeout: () => {},
38
+ // };
39
+ // }
40
+ // options.injectCSS = false
41
+ super({ ...options, content: undefined });
42
+
43
+ // try {
44
+ // globalThis.window = w;
45
+ // } catch(e) {}
46
+ // try {
47
+ // globalThis.document = d;
48
+ // } catch(e) {}
49
+
50
+ // This is a hack to make "initial content detection" by y-prosemirror (and also tiptap isEmpty)
51
+ // properly detect whether or not the document has changed.
52
+ // We change the doc.createAndFill function to make sure the initial block id is set, instead of null
53
+ const schema = this.schema;
54
+ let cache: any;
55
+ const oldCreateAndFill = schema.nodes.doc.createAndFill;
56
+ (schema.nodes.doc as any).createAndFill = (...args: any) => {
57
+ if (cache) {
58
+ return cache;
59
+ }
60
+ const ret = oldCreateAndFill.apply(schema.nodes.doc, args);
61
+
62
+ // create a copy that we can mutate (otherwise, assigning attrs is not safe and corrupts the pm state)
63
+ const jsonNode = JSON.parse(JSON.stringify(ret!.toJSON()));
64
+ jsonNode.content[0].content[0].attrs.id = "initialBlockId";
65
+
66
+ cache = Node.fromJSON(schema, jsonNode);
67
+ return cache;
68
+ };
69
+
70
+ let doc: Node;
71
+
72
+ try {
73
+ const pmNodes = options?.content.map((b) =>
74
+ blockToNode(b, this.schema, styleSchema).toJSON()
75
+ );
76
+ doc = createDocument(
77
+ {
78
+ type: "doc",
79
+ content: [
80
+ {
81
+ type: "blockGroup",
82
+ content: pmNodes,
83
+ },
84
+ ],
85
+ },
86
+ this.schema,
87
+ this.options.parseOptions
88
+ );
89
+ } catch (e) {
90
+ console.error(
91
+ "Error creating document from blocks passed as `initialContent`. Caused by exception: ",
92
+ e
93
+ );
94
+ throw new Error(
95
+ "Error creating document from blocks passed as `initialContent`:\n" +
96
+ +JSON.stringify(options.content)
97
+ );
98
+ }
99
+
100
+ // Create state immediately, so that it's available independently from the View,
101
+ // the way Prosemirror "intends it to be". This also makes sure that we can access
102
+ // the state before the view is created / mounted.
103
+ this._state = EditorState.create({
104
+ doc,
105
+ schema: this.schema,
106
+ // selection: selection || undefined,
107
+ });
108
+ }
109
+
110
+ get state() {
111
+ if (this.view) {
112
+ this._state = this.view.state;
113
+ }
114
+ return this._state;
115
+ }
116
+
117
+ createView() {
118
+ // no-op
119
+ // Disable default call to `createView` in the Editor constructor.
120
+ // We should call `createView` manually only when a DOM element is available
121
+ }
122
+
123
+ /**
124
+ * Replace the default `createView` method with a custom one - which we call on mount
125
+ */
126
+ private createViewAlternative() {
127
+ // Without queueMicrotask, custom IC / styles will give a React FlushSync error
128
+ queueMicrotask(() => {
129
+ this.view = new EditorView(this.options.element, {
130
+ ...this.options.editorProps,
131
+ // @ts-ignore
132
+ dispatchTransaction: this.dispatchTransaction.bind(this),
133
+ state: this.state,
134
+ });
135
+
136
+ // `editor.view` is not yet available at this time.
137
+ // Therefore we will add all plugins and node views directly afterwards.
138
+ const newState = this.state.reconfigure({
139
+ plugins: this.extensionManager.plugins,
140
+ });
141
+
142
+ this.view.updateState(newState);
143
+
144
+ this.createNodeViews();
145
+ });
146
+ }
147
+
148
+ /**
149
+ * Mounts / unmounts the editor to a dom element
150
+ *
151
+ * @param element DOM element to mount to, ur null / undefined to destroy
152
+ */
153
+ public mount = (element?: HTMLElement | null) => {
154
+ if (!element) {
155
+ this.destroy();
156
+ } else {
157
+ this.options.element = element;
158
+ // @ts-ignore
159
+ this.createViewAlternative();
160
+ }
161
+ };
162
+ }
@@ -1,9 +1,5 @@
1
- import {
2
- Block,
3
- BlockSchema,
4
- InlineContentSchema,
5
- StyleSchema,
6
- } from "../schema";
1
+ import { Block } from "../blocks/defaultBlocks";
2
+ import { BlockSchema, InlineContentSchema, StyleSchema } from "../schema";
7
3
 
8
4
  export type TextCursorPosition<
9
5
  BSchema extends BlockSchema,
@@ -1,4 +1,3 @@
1
- @import url("../assets/fonts-inter.css");
2
1
  @import url("prosemirror-tables/style/tables.css");
3
2
 
4
3
  .bn-editor {
@@ -1,9 +1,5 @@
1
- import {
2
- Block,
3
- BlockSchema,
4
- InlineContentSchema,
5
- StyleSchema,
6
- } from "../schema";
1
+ import { Block } from "../blocks/defaultBlocks";
2
+ import { BlockSchema, InlineContentSchema, StyleSchema } from "../schema";
7
3
 
8
4
  export type Selection<
9
5
  BSchema extends BlockSchema,
@@ -3,20 +3,15 @@ import { EditorState, Plugin, PluginKey } from "prosemirror-state";
3
3
  import { EditorView } from "prosemirror-view";
4
4
 
5
5
  import type { BlockNoteEditor } from "../../editor/BlockNoteEditor";
6
- import {
7
- BaseUiElementCallbacks,
8
- BaseUiElementState,
9
- } from "../../extensions-shared/BaseUiElementTypes";
6
+ import { UiElementPosition } from "../../extensions-shared/UiElementPosition";
10
7
  import { BlockSchema, InlineContentSchema, StyleSchema } from "../../schema";
11
8
  import { EventEmitter } from "../../util/EventEmitter";
12
9
 
13
- export type FormattingToolbarCallbacks = BaseUiElementCallbacks;
14
-
15
- export type FormattingToolbarState = BaseUiElementState;
10
+ export type FormattingToolbarState = UiElementPosition;
16
11
 
17
12
  export class FormattingToolbarView {
18
- private formattingToolbarState?: FormattingToolbarState;
19
- public updateFormattingToolbar: () => void;
13
+ public state?: FormattingToolbarState;
14
+ public emitUpdate: () => void;
20
15
 
21
16
  public preventHide = false;
22
17
  public preventShow = false;
@@ -36,18 +31,16 @@ export class FormattingToolbarView {
36
31
  StyleSchema
37
32
  >,
38
33
  private readonly pmView: EditorView,
39
- updateFormattingToolbar: (
40
- formattingToolbarState: FormattingToolbarState
41
- ) => void
34
+ emitUpdate: (state: FormattingToolbarState) => void
42
35
  ) {
43
- this.updateFormattingToolbar = () => {
44
- if (!this.formattingToolbarState) {
36
+ this.emitUpdate = () => {
37
+ if (!this.state) {
45
38
  throw new Error(
46
39
  "Attempting to update uninitialized formatting toolbar"
47
40
  );
48
41
  }
49
42
 
50
- updateFormattingToolbar(this.formattingToolbarState);
43
+ emitUpdate(this.state);
51
44
  };
52
45
 
53
46
  pmView.dom.addEventListener("mousedown", this.viewMousedownHandler);
@@ -72,9 +65,9 @@ export class FormattingToolbarView {
72
65
 
73
66
  // For dragging the whole editor.
74
67
  dragHandler = () => {
75
- if (this.formattingToolbarState?.show) {
76
- this.formattingToolbarState.show = false;
77
- this.updateFormattingToolbar();
68
+ if (this.state?.show) {
69
+ this.state.show = false;
70
+ this.emitUpdate();
78
71
  }
79
72
  };
80
73
 
@@ -105,16 +98,16 @@ export class FormattingToolbarView {
105
98
  return;
106
99
  }
107
100
 
108
- if (this.formattingToolbarState?.show) {
109
- this.formattingToolbarState.show = false;
110
- this.updateFormattingToolbar();
101
+ if (this.state?.show) {
102
+ this.state.show = false;
103
+ this.emitUpdate();
111
104
  }
112
105
  };
113
106
 
114
107
  scrollHandler = () => {
115
- if (this.formattingToolbarState?.show) {
116
- this.formattingToolbarState.referencePos = this.getSelectionBoundingBox();
117
- this.updateFormattingToolbar();
108
+ if (this.state?.show) {
109
+ this.state.referencePos = this.getSelectionBoundingBox();
110
+ this.emitUpdate();
118
111
  }
119
112
  };
120
113
 
@@ -152,24 +145,24 @@ export class FormattingToolbarView {
152
145
  !this.preventShow &&
153
146
  (shouldShow || this.preventHide)
154
147
  ) {
155
- this.formattingToolbarState = {
148
+ this.state = {
156
149
  show: true,
157
150
  referencePos: this.getSelectionBoundingBox(),
158
151
  };
159
152
 
160
- this.updateFormattingToolbar();
153
+ this.emitUpdate();
161
154
 
162
155
  return;
163
156
  }
164
157
 
165
158
  // Checks if menu should be hidden.
166
159
  if (
167
- this.formattingToolbarState?.show &&
160
+ this.state?.show &&
168
161
  !this.preventHide &&
169
162
  (!shouldShow || this.preventShow || !this.editor.isEditable)
170
163
  ) {
171
- this.formattingToolbarState.show = false;
172
- this.updateFormattingToolbar();
164
+ this.state.show = false;
165
+ this.emitUpdate();
173
166
 
174
167
  return;
175
168
  }
@@ -2,12 +2,13 @@ import { getMarkRange, posToDOMRect, Range } from "@tiptap/core";
2
2
  import { EditorView } from "@tiptap/pm/view";
3
3
  import { Mark } from "prosemirror-model";
4
4
  import { Plugin, PluginKey } from "prosemirror-state";
5
+
5
6
  import type { BlockNoteEditor } from "../../editor/BlockNoteEditor";
6
- import { BaseUiElementState } from "../../extensions-shared/BaseUiElementTypes";
7
7
  import { BlockSchema, InlineContentSchema, StyleSchema } from "../../schema";
8
+ import { UiElementPosition } from "../../extensions-shared/UiElementPosition";
8
9
  import { EventEmitter } from "../../util/EventEmitter";
9
10
 
10
- export type HyperlinkToolbarState = BaseUiElementState & {
11
+ export type HyperlinkToolbarState = UiElementPosition & {
11
12
  // The hovered hyperlink's URL, and the text it's displayed with in the
12
13
  // editor.
13
14
  url: string;
@@ -15,8 +16,8 @@ export type HyperlinkToolbarState = BaseUiElementState & {
15
16
  };
16
17
 
17
18
  class HyperlinkToolbarView {
18
- private hyperlinkToolbarState?: HyperlinkToolbarState;
19
- public updateHyperlinkToolbar: () => void;
19
+ public state?: HyperlinkToolbarState;
20
+ public emitUpdate: () => void;
20
21
 
21
22
  menuUpdateTimer: ReturnType<typeof setTimeout> | undefined;
22
23
  startMenuUpdateTimer: () => void;
@@ -34,16 +35,14 @@ class HyperlinkToolbarView {
34
35
  constructor(
35
36
  private readonly editor: BlockNoteEditor<any, any, any>,
36
37
  private readonly pmView: EditorView,
37
- updateHyperlinkToolbar: (
38
- hyperlinkToolbarState: HyperlinkToolbarState
39
- ) => void
38
+ emitUpdate: (state: HyperlinkToolbarState) => void
40
39
  ) {
41
- this.updateHyperlinkToolbar = () => {
42
- if (!this.hyperlinkToolbarState) {
40
+ this.emitUpdate = () => {
41
+ if (!this.state) {
43
42
  throw new Error("Attempting to update uninitialized hyperlink toolbar");
44
43
  }
45
44
 
46
- updateHyperlinkToolbar(this.hyperlinkToolbarState);
45
+ emitUpdate(this.state);
47
46
  };
48
47
 
49
48
  this.startMenuUpdateTimer = () => {
@@ -124,22 +123,22 @@ class HyperlinkToolbarView {
124
123
  editorWrapper.contains(event.target as Node)
125
124
  )
126
125
  ) {
127
- if (this.hyperlinkToolbarState?.show) {
128
- this.hyperlinkToolbarState.show = false;
129
- this.updateHyperlinkToolbar();
126
+ if (this.state?.show) {
127
+ this.state.show = false;
128
+ this.emitUpdate();
130
129
  }
131
130
  }
132
131
  };
133
132
 
134
133
  scrollHandler = () => {
135
134
  if (this.hyperlinkMark !== undefined) {
136
- if (this.hyperlinkToolbarState?.show) {
137
- this.hyperlinkToolbarState.referencePos = posToDOMRect(
135
+ if (this.state?.show) {
136
+ this.state.referencePos = posToDOMRect(
138
137
  this.pmView,
139
138
  this.hyperlinkMarkRange!.from,
140
139
  this.hyperlinkMarkRange!.to
141
140
  );
142
- this.updateHyperlinkToolbar();
141
+ this.emitUpdate();
143
142
  }
144
143
  }
145
144
  };
@@ -158,9 +157,9 @@ class HyperlinkToolbarView {
158
157
  this.pmView.dispatch(tr);
159
158
  this.pmView.focus();
160
159
 
161
- if (this.hyperlinkToolbarState?.show) {
162
- this.hyperlinkToolbarState.show = false;
163
- this.updateHyperlinkToolbar();
160
+ if (this.state?.show) {
161
+ this.state.show = false;
162
+ this.emitUpdate();
164
163
  }
165
164
  }
166
165
 
@@ -176,9 +175,9 @@ class HyperlinkToolbarView {
176
175
  );
177
176
  this.pmView.focus();
178
177
 
179
- if (this.hyperlinkToolbarState?.show) {
180
- this.hyperlinkToolbarState.show = false;
181
- this.updateHyperlinkToolbar();
178
+ if (this.state?.show) {
179
+ this.state.show = false;
180
+ this.emitUpdate();
182
181
  }
183
182
  }
184
183
 
@@ -232,7 +231,7 @@ class HyperlinkToolbarView {
232
231
  }
233
232
 
234
233
  if (this.hyperlinkMark && this.editor.isEditable) {
235
- this.hyperlinkToolbarState = {
234
+ this.state = {
236
235
  show: true,
237
236
  referencePos: posToDOMRect(
238
237
  this.pmView,
@@ -245,19 +244,19 @@ class HyperlinkToolbarView {
245
244
  this.hyperlinkMarkRange!.to
246
245
  ),
247
246
  };
248
- this.updateHyperlinkToolbar();
247
+ this.emitUpdate();
249
248
 
250
249
  return;
251
250
  }
252
251
 
253
252
  // Hides menu.
254
253
  if (
255
- this.hyperlinkToolbarState?.show &&
254
+ this.state?.show &&
256
255
  prevHyperlinkMark &&
257
256
  (!this.hyperlinkMark || !this.editor.isEditable)
258
257
  ) {
259
- this.hyperlinkToolbarState.show = false;
260
- this.updateHyperlinkToolbar();
258
+ this.state.show = false;
259
+ this.emitUpdate();
261
260
 
262
261
  return;
263
262
  }