@blocknote/core 0.1.2 → 0.2.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 (171) hide show
  1. package/README.md +12 -6
  2. package/dist/blocknote.js +1424 -5109
  3. package/dist/blocknote.js.map +1 -1
  4. package/dist/blocknote.umd.cjs +1 -53
  5. package/dist/blocknote.umd.cjs.map +1 -1
  6. package/dist/style.css +1 -1
  7. package/package.json +3 -16
  8. package/src/BlockNoteEditor.ts +54 -0
  9. package/src/BlockNoteExtensions.ts +52 -7
  10. package/src/assets/fonts-inter.css +92 -0
  11. package/src/editor.module.css +37 -0
  12. package/src/extensions/Blocks/BlockAttributes.ts +1 -3
  13. package/src/extensions/Blocks/PreviousBlockTypePlugin.ts +71 -18
  14. package/src/extensions/Blocks/helpers/getBlockInfoFromPos.ts +66 -0
  15. package/src/extensions/Blocks/index.ts +7 -3
  16. package/src/extensions/Blocks/nodes/Block.module.css +116 -74
  17. package/src/extensions/Blocks/nodes/Block.ts +413 -292
  18. package/src/extensions/Blocks/nodes/BlockGroup.ts +6 -6
  19. package/src/extensions/Blocks/nodes/BlockTypes/HeadingBlock/HeadingContent.ts +84 -0
  20. package/src/extensions/Blocks/nodes/BlockTypes/ListItemBlock/ListItemContent.ts +177 -0
  21. package/src/extensions/Blocks/nodes/BlockTypes/ListItemBlock/OrderedListItemIndexPlugin.ts +77 -0
  22. package/src/extensions/Blocks/nodes/BlockTypes/TextBlock/TextContent.ts +34 -0
  23. package/src/extensions/DraggableBlocks/BlockSideMenuFactoryTypes.ts +20 -0
  24. package/src/extensions/DraggableBlocks/DraggableBlocksExtension.ts +27 -9
  25. package/src/extensions/DraggableBlocks/{DraggableBlocksPlugin.tsx → DraggableBlocksPlugin.ts} +227 -147
  26. package/src/extensions/FormattingToolbar/FormattingToolbarExtension.ts +29 -0
  27. package/src/extensions/FormattingToolbar/FormattingToolbarFactoryTypes.ts +35 -0
  28. package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +308 -0
  29. package/src/extensions/HyperlinkToolbar/HyperlinkMark.ts +28 -0
  30. package/src/extensions/HyperlinkToolbar/HyperlinkToolbarFactoryTypes.ts +19 -0
  31. package/src/extensions/HyperlinkToolbar/HyperlinkToolbarPlugin.ts +251 -0
  32. package/src/extensions/Placeholder/PlaceholderExtension.ts +2 -2
  33. package/src/extensions/SlashMenu/SlashMenuExtension.ts +9 -1
  34. package/src/extensions/SlashMenu/SlashMenuItem.ts +1 -3
  35. package/src/extensions/SlashMenu/defaultCommands.tsx +33 -22
  36. package/src/extensions/TrailingNode/TrailingNodeExtension.ts +4 -4
  37. package/src/extensions/UniqueID/UniqueID.ts +14 -1
  38. package/src/index.ts +8 -4
  39. package/src/shared/EditorElement.ts +10 -0
  40. package/src/shared/plugins/suggestion/SuggestionItem.ts +1 -8
  41. package/src/shared/plugins/suggestion/SuggestionPlugin.ts +222 -101
  42. package/src/shared/plugins/suggestion/SuggestionsMenuFactoryTypes.ts +21 -0
  43. package/src/{utils.ts → shared/utils.ts} +0 -0
  44. package/types/src/BlockNoteEditor.d.ts +13 -0
  45. package/types/src/BlockNoteExtensions.d.ts +12 -1
  46. package/types/src/EditorElement.d.ts +7 -0
  47. package/types/src/extensions/Blocks/PreviousBlockTypePlugin.d.ts +1 -1
  48. package/types/src/extensions/Blocks/helpers/getBlockInfoFromPos.d.ts +19 -0
  49. package/types/src/extensions/Blocks/nodes/Block.d.ts +11 -19
  50. package/types/src/extensions/Blocks/nodes/BlockTypes/HeadingBlock/HeadingContent.d.ts +8 -0
  51. package/types/src/extensions/Blocks/nodes/BlockTypes/ListItemBlock/ListItemContent.d.ts +8 -0
  52. package/types/src/extensions/Blocks/nodes/BlockTypes/ListItemBlock/OrderedListItemIndexPlugin.d.ts +2 -0
  53. package/types/src/extensions/Blocks/nodes/BlockTypes/TextBlock/TextContent.d.ts +6 -0
  54. package/types/src/extensions/BubbleMenu/BubbleMenuExtension.d.ts +4 -1
  55. package/types/src/extensions/BubbleMenu/BubbleMenuFactoryTypes.d.ts +27 -0
  56. package/types/src/extensions/BubbleMenu/BubbleMenuPlugin.d.ts +10 -12
  57. package/types/src/extensions/DraggableBlocks/BlockMenuFactoryTypes.d.ts +12 -0
  58. package/types/src/extensions/DraggableBlocks/BlockSideMenuFactoryTypes.d.ts +14 -0
  59. package/types/src/extensions/DraggableBlocks/DragMenuFactoryTypes.d.ts +18 -0
  60. package/types/src/extensions/DraggableBlocks/DraggableBlocksExtension.d.ts +9 -3
  61. package/types/src/extensions/DraggableBlocks/DraggableBlocksPlugin.d.ts +23 -1
  62. package/types/src/extensions/FormattingToolbar/FormattingToolbarExtension.d.ts +8 -0
  63. package/types/src/extensions/FormattingToolbar/FormattingToolbarFactoryTypes.d.ts +23 -0
  64. package/types/src/extensions/FormattingToolbar/FormattingToolbarPlugin.d.ts +43 -0
  65. package/types/src/extensions/HyperlinkToolbar/HyperlinkMark.d.ts +8 -0
  66. package/types/src/extensions/HyperlinkToolbar/HyperlinkToolbarFactoryTypes.d.ts +12 -0
  67. package/types/src/extensions/HyperlinkToolbar/HyperlinkToolbarPlugin.d.ts +11 -0
  68. package/types/src/extensions/Hyperlinks/HyperlinkMark.d.ts +2 -1
  69. package/types/src/extensions/Hyperlinks/HyperlinkMenuFactoryTypes.d.ts +11 -0
  70. package/types/src/extensions/Hyperlinks/HyperlinkMenuPlugin.d.ts +10 -1
  71. package/types/src/extensions/SlashMenu/SlashMenuExtension.d.ts +3 -1
  72. package/types/src/extensions/SlashMenu/SlashMenuItem.d.ts +2 -4
  73. package/types/src/index.d.ts +8 -3
  74. package/types/src/shared/EditorElement.d.ts +6 -0
  75. package/types/src/shared/plugins/suggestion/SuggestionItem.d.ts +1 -6
  76. package/types/src/shared/plugins/suggestion/SuggestionPlugin.d.ts +15 -10
  77. package/types/src/shared/plugins/suggestion/SuggestionsMenuFactoryTypes.d.ts +12 -0
  78. package/types/src/shared/utils.d.ts +2 -0
  79. package/types/src/utils.d.ts +2 -2
  80. package/src/BlockNoteTheme.ts +0 -150
  81. package/src/EditorContent.tsx +0 -2
  82. package/src/extensions/Blocks/OrderedListPlugin.ts +0 -46
  83. package/src/extensions/Blocks/commands/joinBackward.ts +0 -274
  84. package/src/extensions/Blocks/helpers/setBlockHeading.ts +0 -30
  85. package/src/extensions/Blocks/nodes/Content.ts +0 -63
  86. package/src/extensions/Blocks/rule.ts +0 -48
  87. package/src/extensions/BubbleMenu/BubbleMenuExtension.tsx +0 -36
  88. package/src/extensions/BubbleMenu/BubbleMenuPlugin.ts +0 -245
  89. package/src/extensions/BubbleMenu/component/BubbleMenu.tsx +0 -240
  90. package/src/extensions/BubbleMenu/component/LinkToolbarButton.tsx +0 -67
  91. package/src/extensions/DraggableBlocks/components/DragHandle.tsx +0 -102
  92. package/src/extensions/DraggableBlocks/components/DragHandleMenu.tsx +0 -19
  93. package/src/extensions/Hyperlinks/HyperlinkMark.tsx +0 -16
  94. package/src/extensions/Hyperlinks/HyperlinkMenuPlugin.tsx +0 -165
  95. package/src/extensions/Hyperlinks/menus/EditHyperlinkMenu.tsx +0 -44
  96. package/src/extensions/Hyperlinks/menus/EditHyperlinkMenuItem.tsx +0 -34
  97. package/src/extensions/Hyperlinks/menus/EditHyperlinkMenuItemIcon.tsx +0 -31
  98. package/src/extensions/Hyperlinks/menus/EditHyperlinkMenuItemInput.tsx +0 -40
  99. package/src/extensions/Hyperlinks/menus/HoverHyperlinkMenu.tsx +0 -37
  100. package/src/extensions/Hyperlinks/menus/HyperlinkMenu.tsx +0 -63
  101. package/src/fonts-inter.css +0 -94
  102. package/src/globals.css +0 -28
  103. package/src/root.module.css +0 -19
  104. package/src/shared/components/toolbar/Toolbar.tsx +0 -10
  105. package/src/shared/components/toolbar/ToolbarButton.tsx +0 -57
  106. package/src/shared/components/toolbar/ToolbarDropdown.tsx +0 -35
  107. package/src/shared/components/toolbar/ToolbarDropdownItem.tsx +0 -35
  108. package/src/shared/components/toolbar/ToolbarDropdownTarget.tsx +0 -31
  109. package/src/shared/components/tooltip/TooltipContent.module.css +0 -15
  110. package/src/shared/components/tooltip/TooltipContent.tsx +0 -23
  111. package/src/shared/hooks/useEditorForceUpdate.tsx +0 -30
  112. package/src/shared/plugins/suggestion/SuggestionListReactRenderer.tsx +0 -236
  113. package/src/shared/plugins/suggestion/components/SuggestionGroup.tsx +0 -47
  114. package/src/shared/plugins/suggestion/components/SuggestionGroupItem.tsx +0 -82
  115. package/src/shared/plugins/suggestion/components/SuggestionList.tsx +0 -92
  116. package/src/useEditor.ts +0 -51
  117. package/types/src/BlockNoteTheme.d.ts +0 -2
  118. package/types/src/EditorContent.d.ts +0 -1
  119. package/types/src/commands/indentation.d.ts +0 -2
  120. package/types/src/extensions/Blocks/OrderedListPlugin.d.ts +0 -2
  121. package/types/src/extensions/Blocks/commands/joinBackward.d.ts +0 -14
  122. package/types/src/extensions/Blocks/helpers/setBlockHeading.d.ts +0 -5
  123. package/types/src/extensions/Blocks/nodes/Content.d.ts +0 -5
  124. package/types/src/extensions/Blocks/rule.d.ts +0 -16
  125. package/types/src/extensions/BubbleMenu/component/BubbleMenu.d.ts +0 -5
  126. package/types/src/extensions/BubbleMenu/component/DropdownBlockItem.d.ts +0 -10
  127. package/types/src/extensions/BubbleMenu/component/LinkToolbarButton.d.ts +0 -11
  128. package/types/src/extensions/DraggableBlocks/components/DragHandle.d.ts +0 -12
  129. package/types/src/extensions/DraggableBlocks/components/DragHandleMenu.d.ts +0 -6
  130. package/types/src/extensions/Hyperlinks/menus/EditHyperlinkMenu.d.ts +0 -11
  131. package/types/src/extensions/Hyperlinks/menus/EditHyperlinkMenuItem.d.ts +0 -13
  132. package/types/src/extensions/Hyperlinks/menus/EditHyperlinkMenuItemIcon.d.ts +0 -8
  133. package/types/src/extensions/Hyperlinks/menus/EditHyperlinkMenuItemInput.d.ts +0 -9
  134. package/types/src/extensions/Hyperlinks/menus/HoverHyperlinkMenu.d.ts +0 -12
  135. package/types/src/extensions/Hyperlinks/menus/HyperlinkBasicMenu.d.ts +0 -12
  136. package/types/src/extensions/Hyperlinks/menus/HyperlinkEditMenu.d.ts +0 -10
  137. package/types/src/extensions/Hyperlinks/menus/HyperlinkMenu.d.ts +0 -21
  138. package/types/src/extensions/Hyperlinks/menus/atlaskit/PanelTextInput.d.ts +0 -39
  139. package/types/src/extensions/Hyperlinks/menus/atlaskit/PanelTextInputStyles.d.ts +0 -1
  140. package/types/src/extensions/Hyperlinks/menus/atlaskit/ToolbarComponent.d.ts +0 -11
  141. package/types/src/extensions/Hyperlinks/menus/helpers/PanelTextInput.d.ts +0 -39
  142. package/types/src/extensions/Hyperlinks/menus/helpers/PanelTextInputStyles.d.ts +0 -3
  143. package/types/src/extensions/Hyperlinks/menus/helpers/ToolbarComponent.d.ts +0 -13
  144. package/types/src/extensions/helpers/formatKeyboardShortcut.d.ts +0 -1
  145. package/types/src/lib/atlaskit/browser.d.ts +0 -12
  146. package/types/src/nodes/ChildgroupNode.d.ts +0 -28
  147. package/types/src/nodes/patchNodes.d.ts +0 -1
  148. package/types/src/plugins/TreeViewPlugin/index.d.ts +0 -2
  149. package/types/src/plugins/animation.d.ts +0 -2
  150. package/types/src/react/BlockNoteComposer.d.ts +0 -17
  151. package/types/src/react/BlockNotePlugin.d.ts +0 -1
  152. package/types/src/react/index.d.ts +0 -3
  153. package/types/src/react/useBlockNoteSetup.d.ts +0 -2
  154. package/types/src/registerBlockNote.d.ts +0 -2
  155. package/types/src/shared/components/toolbar/SimpleToolbarButton.d.ts +0 -15
  156. package/types/src/shared/components/toolbar/SimpleToolbarDropdown.d.ts +0 -11
  157. package/types/src/shared/components/toolbar/SimpleToolbarDropdownItem.d.ts +0 -11
  158. package/types/src/shared/components/toolbar/Toolbar.d.ts +0 -4
  159. package/types/src/shared/components/toolbar/ToolbarButton.d.ts +0 -15
  160. package/types/src/shared/components/toolbar/ToolbarDropdown.d.ts +0 -17
  161. package/types/src/shared/components/toolbar/ToolbarDropdownItem.d.ts +0 -11
  162. package/types/src/shared/components/toolbar/ToolbarDropdownTarget.d.ts +0 -8
  163. package/types/src/shared/components/toolbar/ToolbarSeparator.d.ts +0 -2
  164. package/types/src/shared/components/tooltip/TooltipContent.d.ts +0 -15
  165. package/types/src/shared/hooks/useEditorForceUpdate.d.ts +0 -2
  166. package/types/src/shared/plugins/suggestion/SuggestionListReactRenderer.d.ts +0 -71
  167. package/types/src/shared/plugins/suggestion/components/SuggestionGroup.d.ts +0 -23
  168. package/types/src/shared/plugins/suggestion/components/SuggestionGroupItem.d.ts +0 -9
  169. package/types/src/shared/plugins/suggestion/components/SuggestionList.d.ts +0 -11
  170. package/types/src/themes/BlockNoteEditorTheme.d.ts +0 -11
  171. package/types/src/useEditor.d.ts +0 -11
@@ -1,245 +0,0 @@
1
- import {
2
- Editor,
3
- isNodeSelection,
4
- isTextSelection,
5
- posToDOMRect,
6
- } from "@tiptap/core";
7
- import { EditorState, Plugin, PluginKey } from "prosemirror-state";
8
- import { EditorView } from "prosemirror-view";
9
- import tippy, { Instance, Props } from "tippy.js";
10
-
11
- // Same as TipTap bubblemenu plugin, but with these changes:
12
- // https://github.com/ueberdosis/tiptap/pull/2596/files
13
- export interface BubbleMenuPluginProps {
14
- pluginKey: PluginKey | string;
15
- editor: Editor;
16
- element: HTMLElement;
17
- tippyOptions?: Partial<Props>;
18
- shouldShow?:
19
- | ((props: {
20
- editor: Editor;
21
- view: EditorView;
22
- state: EditorState;
23
- oldState?: EditorState;
24
- from: number;
25
- to: number;
26
- }) => boolean)
27
- | null;
28
- }
29
-
30
- export type BubbleMenuViewProps = BubbleMenuPluginProps & {
31
- view: EditorView;
32
- };
33
-
34
- export class BubbleMenuView {
35
- public editor: Editor;
36
-
37
- public element: HTMLElement;
38
-
39
- public view: EditorView;
40
-
41
- public preventHide = false;
42
-
43
- public preventShow = false;
44
-
45
- public tippy: Instance | undefined;
46
-
47
- public tippyOptions?: Partial<Props>;
48
-
49
- public shouldShow: Exclude<BubbleMenuPluginProps["shouldShow"], null> = ({
50
- view,
51
- state,
52
- from,
53
- to,
54
- }) => {
55
- const { doc, selection } = state;
56
- const { empty } = selection;
57
-
58
- // Sometime check for `empty` is not enough.
59
- // Doubleclick an empty paragraph returns a node size of 2.
60
- // So we check also for an empty text size.
61
- const isEmptyTextBlock =
62
- !doc.textBetween(from, to).length && isTextSelection(state.selection);
63
-
64
- if (!view.hasFocus() || empty || isEmptyTextBlock) {
65
- return false;
66
- }
67
-
68
- return true;
69
- };
70
-
71
- constructor({
72
- editor,
73
- element,
74
- view,
75
- tippyOptions = {},
76
- shouldShow,
77
- }: BubbleMenuViewProps) {
78
- this.editor = editor;
79
- this.element = element;
80
- this.view = view;
81
-
82
- if (shouldShow) {
83
- this.shouldShow = shouldShow;
84
- }
85
-
86
- this.element.addEventListener("mousedown", this.mousedownHandler, {
87
- capture: true,
88
- });
89
- this.view.dom.addEventListener("mousedown", this.viewMousedownHandler);
90
- this.view.dom.addEventListener("mouseup", this.viewMouseupHandler);
91
- this.view.dom.addEventListener("dragstart", this.dragstartHandler);
92
-
93
- this.editor.on("focus", this.focusHandler);
94
- this.editor.on("blur", this.blurHandler);
95
- this.tippyOptions = tippyOptions;
96
- // Detaches menu content from its current parent
97
- this.element.remove();
98
- this.element.style.visibility = "visible";
99
- }
100
-
101
- mousedownHandler = () => {
102
- this.preventHide = true;
103
- };
104
-
105
- viewMousedownHandler = () => {
106
- this.preventShow = true;
107
- };
108
-
109
- viewMouseupHandler = () => {
110
- this.preventShow = false;
111
- setTimeout(() => this.update(this.editor.view));
112
- };
113
-
114
- dragstartHandler = () => {
115
- this.hide();
116
- };
117
-
118
- focusHandler = () => {
119
- // we use `setTimeout` to make sure `selection` is already updated
120
- setTimeout(() => this.update(this.editor.view));
121
- };
122
-
123
- blurHandler = ({ event }: { event: FocusEvent }) => {
124
- if (this.preventHide) {
125
- this.preventHide = false;
126
-
127
- return;
128
- }
129
-
130
- if (
131
- event?.relatedTarget &&
132
- this.element.parentNode?.contains(event.relatedTarget as Node)
133
- ) {
134
- return;
135
- }
136
-
137
- this.hide();
138
- };
139
-
140
- createTooltip() {
141
- const { element: editorElement } = this.editor.options;
142
- const editorIsAttached = !!editorElement.parentElement;
143
-
144
- if (this.tippy || !editorIsAttached) {
145
- return;
146
- }
147
-
148
- this.tippy = tippy(editorElement, {
149
- duration: 0,
150
- getReferenceClientRect: null,
151
- content: this.element,
152
- interactive: true,
153
- trigger: "manual",
154
- placement: "top",
155
- hideOnClick: "toggle",
156
- ...this.tippyOptions,
157
- });
158
-
159
- // maybe we have to hide tippy on its own blur event as well
160
- if (this.tippy.popper.firstChild) {
161
- (this.tippy.popper.firstChild as HTMLElement).addEventListener(
162
- "blur",
163
- (event) => {
164
- this.blurHandler({ event });
165
- }
166
- );
167
- }
168
- }
169
-
170
- update(view: EditorView, oldState?: EditorState) {
171
- const { state, composing } = view;
172
- const { doc, selection } = state;
173
- const isSame =
174
- oldState && oldState.doc.eq(doc) && oldState.selection.eq(selection);
175
-
176
- if (composing || isSame) {
177
- return;
178
- }
179
-
180
- this.createTooltip();
181
-
182
- // support for CellSelections
183
- const { ranges } = selection;
184
- const from = Math.min(...ranges.map((range) => range.$from.pos));
185
- const to = Math.max(...ranges.map((range) => range.$to.pos));
186
-
187
- const shouldShow = this.shouldShow?.({
188
- editor: this.editor,
189
- view,
190
- state,
191
- oldState,
192
- from,
193
- to,
194
- });
195
-
196
- if (!shouldShow || this.preventShow) {
197
- this.hide();
198
-
199
- return;
200
- }
201
-
202
- this.tippy?.setProps({
203
- getReferenceClientRect: () => {
204
- if (isNodeSelection(state.selection)) {
205
- const node = view.nodeDOM(from) as HTMLElement;
206
-
207
- if (node) {
208
- return node.getBoundingClientRect();
209
- }
210
- }
211
-
212
- return posToDOMRect(view, from, to);
213
- },
214
- });
215
-
216
- this.show();
217
- }
218
-
219
- show() {
220
- this.tippy?.show();
221
- }
222
-
223
- hide() {
224
- this.tippy?.hide();
225
- }
226
-
227
- destroy() {
228
- this.tippy?.destroy();
229
- this.element.removeEventListener("mousedown", this.mousedownHandler, {
230
- capture: true,
231
- });
232
- this.view.dom.removeEventListener("mousedown", this.viewMousedownHandler);
233
- this.view.dom.removeEventListener("mouseup", this.viewMouseupHandler);
234
- this.view.dom.removeEventListener("dragstart", this.dragstartHandler);
235
- this.editor.off("focus", this.focusHandler);
236
- this.editor.off("blur", this.blurHandler);
237
- }
238
- }
239
-
240
- export const createBubbleMenuPlugin = (options: BubbleMenuPluginProps) => {
241
- return new Plugin({
242
- key: new PluginKey("BubbleMenuPlugin"),
243
- view: (view) => new BubbleMenuView({ view, ...options }),
244
- });
245
- };
@@ -1,240 +0,0 @@
1
- import { Editor } from "@tiptap/core";
2
- import {
3
- RiBold,
4
- RiH1,
5
- RiH2,
6
- RiH3,
7
- RiIndentDecrease,
8
- RiIndentIncrease,
9
- RiItalic,
10
- RiLink,
11
- RiListOrdered,
12
- RiListUnordered,
13
- RiStrikethrough,
14
- RiText,
15
- RiUnderline,
16
- } from "react-icons/ri";
17
- import { ToolbarButton } from "../../../shared/components/toolbar/ToolbarButton";
18
- import { ToolbarDropdown } from "../../../shared/components/toolbar/ToolbarDropdown";
19
- import { Toolbar } from "../../../shared/components/toolbar/Toolbar";
20
- import { useEditorForceUpdate } from "../../../shared/hooks/useEditorForceUpdate";
21
- import { findBlock } from "../../Blocks/helpers/findBlock";
22
- import { formatKeyboardShortcut } from "../../../utils";
23
- import LinkToolbarButton from "./LinkToolbarButton";
24
- import { IconType } from "react-icons";
25
-
26
- type ListType = "li" | "oli";
27
-
28
- function getBlockName(
29
- currentBlockHeading: number | undefined,
30
- currentBlockListType: ListType | undefined
31
- ) {
32
- const headings = ["Heading 1", "Heading 2", "Heading 3"];
33
- const lists = {
34
- li: "Bullet List",
35
- oli: "Numbered List",
36
- };
37
- // A heading that's also a list, should show as Heading
38
- if (currentBlockHeading) {
39
- return headings[currentBlockHeading - 1];
40
- } else if (currentBlockListType) {
41
- return lists[currentBlockListType];
42
- } else {
43
- return "Text";
44
- }
45
- }
46
-
47
- // TODO: add list options, indentation
48
- export const BubbleMenu = (props: { editor: Editor }) => {
49
- useEditorForceUpdate(props.editor);
50
-
51
- const currentBlock = findBlock(props.editor.state.selection);
52
- const currentBlockHeading: number | undefined =
53
- currentBlock?.node.attrs.headingType;
54
- const currentBlockListType: ListType | undefined =
55
- currentBlock?.node.attrs.listType;
56
-
57
- const currentBlockName = getBlockName(
58
- currentBlockHeading,
59
- currentBlockListType
60
- );
61
-
62
- const blockIconMap: Record<string, IconType> = {
63
- Text: RiText,
64
- "Heading 1": RiH1,
65
- "Heading 2": RiH2,
66
- "Heading 3": RiH3,
67
- "Bullet List": RiListUnordered,
68
- "Numbered List": RiListOrdered,
69
- };
70
-
71
- return (
72
- <Toolbar>
73
- <ToolbarDropdown
74
- text={currentBlockName}
75
- icon={blockIconMap[currentBlockName]}
76
- items={[
77
- {
78
- onClick: () => {
79
- // Setting editor focus using a chained command instead causes bubble menu to flicker on click.
80
- props.editor.view.focus();
81
- props.editor.chain().unsetBlockHeading().unsetList().run();
82
- },
83
- text: "Text",
84
- icon: RiText,
85
- isSelected: currentBlockName === "Text",
86
- },
87
- {
88
- onClick: () => {
89
- props.editor.view.focus();
90
- props.editor
91
- .chain()
92
- .unsetList()
93
- .setBlockHeading({ level: "1" })
94
- .run();
95
- },
96
- text: "Heading 1",
97
- icon: RiH1,
98
- isSelected: currentBlockName === "Heading 1",
99
- },
100
- {
101
- onClick: () => {
102
- props.editor.view.focus();
103
- props.editor
104
- .chain()
105
- .unsetList()
106
- .setBlockHeading({ level: "2" })
107
- .run();
108
- },
109
- text: "Heading 2",
110
- icon: RiH2,
111
- isSelected: currentBlockName === "Heading 2",
112
- },
113
- {
114
- onClick: () => {
115
- props.editor.view.focus();
116
- props.editor
117
- .chain()
118
- .unsetList()
119
- .setBlockHeading({ level: "3" })
120
- .run();
121
- },
122
- text: "Heading 3",
123
- icon: RiH3,
124
- isSelected: currentBlockName === "Heading 3",
125
- },
126
- {
127
- onClick: () => {
128
- props.editor.view.focus();
129
- props.editor.chain().unsetBlockHeading().setBlockList("li").run();
130
- },
131
- text: "Bullet List",
132
- icon: RiListUnordered,
133
- isSelected: currentBlockName === "Bullet List",
134
- },
135
- {
136
- onClick: () => {
137
- props.editor.view.focus();
138
- props.editor
139
- .chain()
140
- .unsetBlockHeading()
141
- .setBlockList("oli")
142
- .run();
143
- },
144
- text: "Numbered List",
145
- icon: RiListOrdered,
146
- isSelected: currentBlockName === "Numbered List",
147
- },
148
- ]}
149
- />
150
- <ToolbarButton
151
- onClick={() => {
152
- // Setting editor focus using a chained command instead causes bubble menu to flicker on click.
153
- props.editor.view.focus();
154
- props.editor.commands.toggleBold();
155
- }}
156
- isSelected={props.editor.isActive("bold")}
157
- mainTooltip="Bold"
158
- secondaryTooltip={formatKeyboardShortcut("Mod+B")}
159
- icon={RiBold}
160
- />
161
- <ToolbarButton
162
- onClick={() => {
163
- props.editor.view.focus();
164
- props.editor.commands.toggleItalic();
165
- }}
166
- isSelected={props.editor.isActive("italic")}
167
- mainTooltip="Italic"
168
- secondaryTooltip={formatKeyboardShortcut("Mod+I")}
169
- icon={RiItalic}
170
- />
171
- <ToolbarButton
172
- onClick={() => {
173
- props.editor.view.focus();
174
- props.editor.commands.toggleUnderline();
175
- }}
176
- isSelected={props.editor.isActive("underline")}
177
- mainTooltip="Underline"
178
- secondaryTooltip={formatKeyboardShortcut("Mod+U")}
179
- icon={RiUnderline}
180
- />
181
- <ToolbarButton
182
- onClick={() => {
183
- props.editor.view.focus();
184
- props.editor.commands.toggleStrike();
185
- }}
186
- isSelected={props.editor.isActive("strike")}
187
- mainTooltip="Strike-through"
188
- secondaryTooltip={formatKeyboardShortcut("Mod+Shift+X")}
189
- icon={RiStrikethrough}
190
- />
191
- <ToolbarButton
192
- onClick={() => {
193
- props.editor.view.focus();
194
- props.editor.commands.sinkListItem("block");
195
- }}
196
- isDisabled={!props.editor.can().sinkListItem("block")}
197
- mainTooltip="Indent"
198
- secondaryTooltip={formatKeyboardShortcut("Tab")}
199
- icon={RiIndentIncrease}
200
- />
201
-
202
- <ToolbarButton
203
- onClick={() => {
204
- props.editor.view.focus();
205
- props.editor.commands.liftListItem("block");
206
- }}
207
- isDisabled={
208
- !props.editor.can().command(({ state }) => {
209
- const block = findBlock(state.selection);
210
- if (!block) {
211
- return false;
212
- }
213
- // If the depth is greater than 2 you can lift
214
- return block.depth > 2;
215
- })
216
- }
217
- mainTooltip="Decrease Indent"
218
- secondaryTooltip={formatKeyboardShortcut("Shift+Tab")}
219
- icon={RiIndentDecrease}
220
- />
221
-
222
- <LinkToolbarButton
223
- // editor={props.editor}
224
- isSelected={props.editor.isActive("link")}
225
- mainTooltip="Link"
226
- secondaryTooltip={formatKeyboardShortcut("Mod+K")}
227
- icon={RiLink}
228
- editor={props.editor}
229
- />
230
- {/* <SimpleBubbleMenuButton
231
- editor={props.editor}
232
- onClick={() => {
233
- const comment = this.props.commentStore.createComment();
234
- props.editor.chain().focus().setComment(comment.id).run();
235
- }}
236
- styleDetails={comment}
237
- /> */}
238
- </Toolbar>
239
- );
240
- };
@@ -1,67 +0,0 @@
1
- import Tippy from "@tippyjs/react";
2
- import { Editor } from "@tiptap/core";
3
- import { useCallback, useState } from "react";
4
- import {
5
- ToolbarButton,
6
- ToolbarButtonProps,
7
- } from "../../../shared/components/toolbar/ToolbarButton";
8
- import { EditHyperlinkMenu } from "../../Hyperlinks/menus/EditHyperlinkMenu";
9
-
10
- type Props = ToolbarButtonProps & {
11
- editor: Editor;
12
- };
13
-
14
- /**
15
- * The link menu button opens a tooltip on click
16
- */
17
- export const LinkToolbarButton = (props: Props) => {
18
- const [creationMenu, setCreationMenu] = useState<any>();
19
-
20
- // TODO: review code; does this pattern still make sense?
21
- const updateCreationMenu = useCallback(() => {
22
- const onSubmit = (url: string, text: string) => {
23
- if (url === "") {
24
- return;
25
- }
26
- const mark = props.editor.schema.mark("link", { href: url });
27
- let { from, to } = props.editor.state.selection;
28
- props.editor.view.dispatch(
29
- props.editor.view.state.tr
30
- .insertText(text, from, to)
31
- .addMark(from, from + text.length, mark)
32
- );
33
- };
34
-
35
- // get the currently selected text and url from the document, and use it to
36
- // create a new creation menu
37
- const { from, to } = props.editor.state.selection;
38
- const selectedText = props.editor.state.doc.textBetween(from, to);
39
- const activeUrl = props.editor.isActive("link")
40
- ? props.editor.getAttributes("link").href || ""
41
- : "";
42
-
43
- setCreationMenu(
44
- <EditHyperlinkMenu
45
- key={Math.random() + ""} // Math.random to prevent old element from being re-used
46
- url={activeUrl}
47
- text={selectedText}
48
- update={onSubmit}
49
- />
50
- );
51
- }, [props.editor]);
52
-
53
- return (
54
- <Tippy
55
- content={creationMenu}
56
- trigger={"click"}
57
- onShow={(_) => {
58
- updateCreationMenu();
59
- }}
60
- interactive={true}
61
- maxWidth={500}>
62
- <ToolbarButton {...props} />
63
- </Tippy>
64
- );
65
- };
66
-
67
- export default LinkToolbarButton;
@@ -1,102 +0,0 @@
1
- import { TextSelection } from "prosemirror-state";
2
- import { EditorView } from "prosemirror-view";
3
- import { useState } from "react";
4
- import { AiOutlinePlus } from "react-icons/ai";
5
- import { findBlock } from "../../Blocks/helpers/findBlock";
6
- import { SlashMenuPluginKey } from "../../SlashMenu/SlashMenuExtension";
7
- import { Menu } from "@mantine/core";
8
- import { MdDragIndicator } from "react-icons/all";
9
- import { ActionIcon } from "@mantine/core";
10
- import DragHandleMenu from "./DragHandleMenu";
11
-
12
- export const DragHandle = (props: {
13
- view: EditorView;
14
- coords: { left: number; top: number };
15
- onShow?: () => void;
16
- onHide?: () => void;
17
- onAddClicked?: () => void;
18
- }) => {
19
- const [clicked, setClicked] = useState<boolean>(false);
20
- const [deleted, setDeleted] = useState<boolean>(false);
21
-
22
- const onDelete = () => {
23
- const pos = props.view.posAtCoords(props.coords);
24
- if (!pos) {
25
- return;
26
- }
27
- const currentBlock = findBlock(
28
- TextSelection.create(props.view.state.doc, pos.pos)
29
- );
30
-
31
- if (currentBlock) {
32
- if (props.view.dispatch) {
33
- props.view.dispatch(
34
- props.view.state.tr.deleteRange(
35
- currentBlock.pos,
36
- currentBlock.pos + currentBlock.node.nodeSize
37
- )
38
- );
39
- }
40
- setDeleted(true);
41
- }
42
- };
43
-
44
- const onAddClick = () => {
45
- setClicked(true);
46
- if (props.onAddClicked) {
47
- props.onAddClicked();
48
- }
49
- const pos = props.view.posAtCoords(props.coords);
50
- if (!pos) {
51
- return;
52
- }
53
- const currentBlock = findBlock(
54
- TextSelection.create(props.view.state.doc, pos.pos)
55
- );
56
- if (!currentBlock) {
57
- return;
58
- }
59
- // If current blocks content is empty dont create a new block
60
- if (currentBlock.node.firstChild?.textContent.length !== 0) {
61
- // Create new block after current block
62
- const endOfBlock = currentBlock.pos + currentBlock.node.nodeSize;
63
- let newBlock = props.view.state.schema.nodes["content"].createAndFill()!;
64
- props.view.state.tr.insert(endOfBlock, newBlock);
65
- props.view.dispatch(props.view.state.tr.insert(endOfBlock, newBlock));
66
- props.view.dispatch(
67
- props.view.state.tr.setSelection(
68
- new TextSelection(props.view.state.tr.doc.resolve(endOfBlock + 1))
69
- )
70
- );
71
- }
72
- // Focus and activate slash menu
73
- props.view.focus();
74
- props.view.dispatch(
75
- props.view.state.tr.scrollIntoView().setMeta(SlashMenuPluginKey, {
76
- // TODO import suggestion plugin key
77
- activate: true,
78
- type: "drag",
79
- })
80
- );
81
- };
82
-
83
- if (deleted || clicked) {
84
- return null;
85
- }
86
-
87
- return (
88
- <div style={{ display: "flex", flexDirection: "row" }}>
89
- <ActionIcon size={24} color={"brandFinal.3"} data-test={"dragHandleAdd"}>
90
- {<AiOutlinePlus size={24} onClick={onAddClick} />}
91
- </ActionIcon>
92
- <Menu onOpen={props.onShow} onClose={props.onHide} position={"left"}>
93
- <Menu.Target>
94
- <ActionIcon size={24} color={"brandFinal.3"} data-test={"dragHandle"}>
95
- {<MdDragIndicator size={24} />}
96
- </ActionIcon>
97
- </Menu.Target>
98
- <DragHandleMenu onDelete={onDelete} />
99
- </Menu>
100
- </div>
101
- );
102
- };
@@ -1,19 +0,0 @@
1
- import { createStyles, Menu } from "@mantine/core";
2
-
3
- type Props = {
4
- onDelete: () => void;
5
- };
6
-
7
- const DragHandleMenu = (props: Props) => {
8
- const { classes } = createStyles({ root: {} })(undefined, {
9
- name: "DragHandleMenu",
10
- });
11
-
12
- return (
13
- <Menu.Dropdown className={classes.root}>
14
- <Menu.Item onClick={props.onDelete}>Delete</Menu.Item>
15
- </Menu.Dropdown>
16
- );
17
- };
18
-
19
- export default DragHandleMenu;
@@ -1,16 +0,0 @@
1
- import { Link } from "@tiptap/extension-link";
2
- import { createHyperlinkMenuPlugin } from "./HyperlinkMenuPlugin";
3
-
4
- /**
5
- * This custom link includes a special menu for editing/deleting/opening the link.
6
- * The menu will be triggered by hovering over the link with the mouse,
7
- * or by moving the cursor inside the link text
8
- */
9
- const Hyperlink = Link.extend({
10
- priority: 500,
11
- addProseMirrorPlugins() {
12
- return [...(this.parent?.() || []), createHyperlinkMenuPlugin()];
13
- },
14
- });
15
-
16
- export default Hyperlink;