@blocknote/core 0.1.2 → 0.2.1-alpha.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.
- package/README.md +12 -6
- package/dist/blocknote.js +1425 -5109
- package/dist/blocknote.js.map +1 -1
- package/dist/blocknote.umd.cjs +1 -53
- package/dist/blocknote.umd.cjs.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +19 -32
- package/src/BlockNoteEditor.ts +54 -0
- package/src/BlockNoteExtensions.ts +52 -7
- package/src/assets/fonts-inter.css +92 -0
- package/src/editor.module.css +37 -0
- package/src/extensions/Blocks/BlockAttributes.ts +1 -3
- package/src/extensions/Blocks/PreviousBlockTypePlugin.ts +71 -18
- package/src/extensions/Blocks/helpers/getBlockInfoFromPos.ts +66 -0
- package/src/extensions/Blocks/index.ts +7 -3
- package/src/extensions/Blocks/nodes/Block.module.css +116 -74
- package/src/extensions/Blocks/nodes/Block.ts +413 -292
- package/src/extensions/Blocks/nodes/BlockGroup.ts +6 -6
- package/src/extensions/Blocks/nodes/BlockTypes/HeadingBlock/HeadingContent.ts +84 -0
- package/src/extensions/Blocks/nodes/BlockTypes/ListItemBlock/ListItemContent.ts +177 -0
- package/src/extensions/Blocks/nodes/BlockTypes/ListItemBlock/OrderedListItemIndexPlugin.ts +77 -0
- package/src/extensions/Blocks/nodes/BlockTypes/TextBlock/TextContent.ts +34 -0
- package/src/extensions/DraggableBlocks/BlockSideMenuFactoryTypes.ts +20 -0
- package/src/extensions/DraggableBlocks/DraggableBlocksExtension.ts +27 -9
- package/src/extensions/DraggableBlocks/{DraggableBlocksPlugin.tsx → DraggableBlocksPlugin.ts} +227 -147
- package/src/extensions/FormattingToolbar/FormattingToolbarExtension.ts +29 -0
- package/src/extensions/FormattingToolbar/FormattingToolbarFactoryTypes.ts +35 -0
- package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +308 -0
- package/src/extensions/HyperlinkToolbar/HyperlinkMark.ts +28 -0
- package/src/extensions/HyperlinkToolbar/HyperlinkToolbarFactoryTypes.ts +19 -0
- package/src/extensions/HyperlinkToolbar/HyperlinkToolbarPlugin.ts +251 -0
- package/src/extensions/Placeholder/PlaceholderExtension.ts +5 -2
- package/src/extensions/SlashMenu/SlashMenuExtension.ts +9 -1
- package/src/extensions/SlashMenu/SlashMenuItem.ts +1 -3
- package/src/extensions/SlashMenu/defaultCommands.tsx +33 -22
- package/src/extensions/TrailingNode/TrailingNodeExtension.ts +4 -4
- package/src/extensions/UniqueID/UniqueID.ts +14 -1
- package/src/index.ts +8 -4
- package/src/shared/EditorElement.ts +10 -0
- package/src/shared/plugins/suggestion/SuggestionItem.ts +1 -8
- package/src/shared/plugins/suggestion/SuggestionPlugin.ts +222 -101
- package/src/shared/plugins/suggestion/SuggestionsMenuFactoryTypes.ts +21 -0
- package/src/{utils.ts → shared/utils.ts} +0 -0
- package/types/src/BlockNoteEditor.d.ts +13 -0
- package/types/src/BlockNoteExtensions.d.ts +12 -1
- package/types/src/EditorElement.d.ts +7 -0
- package/types/src/extensions/Blocks/PreviousBlockTypePlugin.d.ts +1 -1
- package/types/src/extensions/Blocks/helpers/getBlockInfoFromPos.d.ts +19 -0
- package/types/src/extensions/Blocks/nodes/Block.d.ts +11 -19
- package/types/src/extensions/Blocks/nodes/BlockTypes/HeadingBlock/HeadingContent.d.ts +8 -0
- package/types/src/extensions/Blocks/nodes/BlockTypes/ListItemBlock/ListItemContent.d.ts +8 -0
- package/types/src/extensions/Blocks/nodes/BlockTypes/ListItemBlock/OrderedListItemIndexPlugin.d.ts +2 -0
- package/types/src/extensions/Blocks/nodes/BlockTypes/TextBlock/TextContent.d.ts +6 -0
- package/types/src/extensions/BubbleMenu/BubbleMenuExtension.d.ts +4 -1
- package/types/src/extensions/BubbleMenu/BubbleMenuFactoryTypes.d.ts +27 -0
- package/types/src/extensions/BubbleMenu/BubbleMenuPlugin.d.ts +10 -12
- package/types/src/extensions/DraggableBlocks/BlockMenuFactoryTypes.d.ts +12 -0
- package/types/src/extensions/DraggableBlocks/BlockSideMenuFactoryTypes.d.ts +14 -0
- package/types/src/extensions/DraggableBlocks/DragMenuFactoryTypes.d.ts +18 -0
- package/types/src/extensions/DraggableBlocks/DraggableBlocksExtension.d.ts +9 -3
- package/types/src/extensions/DraggableBlocks/DraggableBlocksPlugin.d.ts +23 -1
- package/types/src/extensions/FormattingToolbar/FormattingToolbarExtension.d.ts +8 -0
- package/types/src/extensions/FormattingToolbar/FormattingToolbarFactoryTypes.d.ts +23 -0
- package/types/src/extensions/FormattingToolbar/FormattingToolbarPlugin.d.ts +43 -0
- package/types/src/extensions/HyperlinkToolbar/HyperlinkMark.d.ts +8 -0
- package/types/src/extensions/HyperlinkToolbar/HyperlinkToolbarFactoryTypes.d.ts +12 -0
- package/types/src/extensions/HyperlinkToolbar/HyperlinkToolbarPlugin.d.ts +11 -0
- package/types/src/extensions/Hyperlinks/HyperlinkMark.d.ts +2 -1
- package/types/src/extensions/Hyperlinks/HyperlinkMenuFactoryTypes.d.ts +11 -0
- package/types/src/extensions/Hyperlinks/HyperlinkMenuPlugin.d.ts +10 -1
- package/types/src/extensions/SlashMenu/SlashMenuExtension.d.ts +3 -1
- package/types/src/extensions/SlashMenu/SlashMenuItem.d.ts +2 -4
- package/types/src/index.d.ts +8 -3
- package/types/src/shared/EditorElement.d.ts +6 -0
- package/types/src/shared/plugins/suggestion/SuggestionItem.d.ts +1 -6
- package/types/src/shared/plugins/suggestion/SuggestionPlugin.d.ts +15 -10
- package/types/src/shared/plugins/suggestion/SuggestionsMenuFactoryTypes.d.ts +12 -0
- package/types/src/shared/utils.d.ts +2 -0
- package/types/src/utils.d.ts +2 -2
- package/src/BlockNoteTheme.ts +0 -150
- package/src/EditorContent.tsx +0 -2
- package/src/extensions/Blocks/OrderedListPlugin.ts +0 -46
- package/src/extensions/Blocks/commands/joinBackward.ts +0 -274
- package/src/extensions/Blocks/helpers/setBlockHeading.ts +0 -30
- package/src/extensions/Blocks/nodes/Content.ts +0 -63
- package/src/extensions/Blocks/rule.ts +0 -48
- package/src/extensions/BubbleMenu/BubbleMenuExtension.tsx +0 -36
- package/src/extensions/BubbleMenu/BubbleMenuPlugin.ts +0 -245
- package/src/extensions/BubbleMenu/component/BubbleMenu.tsx +0 -240
- package/src/extensions/BubbleMenu/component/LinkToolbarButton.tsx +0 -67
- package/src/extensions/DraggableBlocks/components/DragHandle.tsx +0 -102
- package/src/extensions/DraggableBlocks/components/DragHandleMenu.tsx +0 -19
- package/src/extensions/Hyperlinks/HyperlinkMark.tsx +0 -16
- package/src/extensions/Hyperlinks/HyperlinkMenuPlugin.tsx +0 -165
- package/src/extensions/Hyperlinks/menus/EditHyperlinkMenu.tsx +0 -44
- package/src/extensions/Hyperlinks/menus/EditHyperlinkMenuItem.tsx +0 -34
- package/src/extensions/Hyperlinks/menus/EditHyperlinkMenuItemIcon.tsx +0 -31
- package/src/extensions/Hyperlinks/menus/EditHyperlinkMenuItemInput.tsx +0 -40
- package/src/extensions/Hyperlinks/menus/HoverHyperlinkMenu.tsx +0 -37
- package/src/extensions/Hyperlinks/menus/HyperlinkMenu.tsx +0 -63
- package/src/fonts-inter.css +0 -94
- package/src/globals.css +0 -28
- package/src/root.module.css +0 -19
- package/src/shared/components/toolbar/Toolbar.tsx +0 -10
- package/src/shared/components/toolbar/ToolbarButton.tsx +0 -57
- package/src/shared/components/toolbar/ToolbarDropdown.tsx +0 -35
- package/src/shared/components/toolbar/ToolbarDropdownItem.tsx +0 -35
- package/src/shared/components/toolbar/ToolbarDropdownTarget.tsx +0 -31
- package/src/shared/components/tooltip/TooltipContent.module.css +0 -15
- package/src/shared/components/tooltip/TooltipContent.tsx +0 -23
- package/src/shared/hooks/useEditorForceUpdate.tsx +0 -30
- package/src/shared/plugins/suggestion/SuggestionListReactRenderer.tsx +0 -236
- package/src/shared/plugins/suggestion/components/SuggestionGroup.tsx +0 -47
- package/src/shared/plugins/suggestion/components/SuggestionGroupItem.tsx +0 -82
- package/src/shared/plugins/suggestion/components/SuggestionList.tsx +0 -92
- package/src/useEditor.ts +0 -51
- package/types/src/BlockNoteTheme.d.ts +0 -2
- package/types/src/EditorContent.d.ts +0 -1
- package/types/src/commands/indentation.d.ts +0 -2
- package/types/src/extensions/Blocks/OrderedListPlugin.d.ts +0 -2
- package/types/src/extensions/Blocks/commands/joinBackward.d.ts +0 -14
- package/types/src/extensions/Blocks/helpers/setBlockHeading.d.ts +0 -5
- package/types/src/extensions/Blocks/nodes/Content.d.ts +0 -5
- package/types/src/extensions/Blocks/rule.d.ts +0 -16
- package/types/src/extensions/BubbleMenu/component/BubbleMenu.d.ts +0 -5
- package/types/src/extensions/BubbleMenu/component/DropdownBlockItem.d.ts +0 -10
- package/types/src/extensions/BubbleMenu/component/LinkToolbarButton.d.ts +0 -11
- package/types/src/extensions/DraggableBlocks/components/DragHandle.d.ts +0 -12
- package/types/src/extensions/DraggableBlocks/components/DragHandleMenu.d.ts +0 -6
- package/types/src/extensions/Hyperlinks/menus/EditHyperlinkMenu.d.ts +0 -11
- package/types/src/extensions/Hyperlinks/menus/EditHyperlinkMenuItem.d.ts +0 -13
- package/types/src/extensions/Hyperlinks/menus/EditHyperlinkMenuItemIcon.d.ts +0 -8
- package/types/src/extensions/Hyperlinks/menus/EditHyperlinkMenuItemInput.d.ts +0 -9
- package/types/src/extensions/Hyperlinks/menus/HoverHyperlinkMenu.d.ts +0 -12
- package/types/src/extensions/Hyperlinks/menus/HyperlinkBasicMenu.d.ts +0 -12
- package/types/src/extensions/Hyperlinks/menus/HyperlinkEditMenu.d.ts +0 -10
- package/types/src/extensions/Hyperlinks/menus/HyperlinkMenu.d.ts +0 -21
- package/types/src/extensions/Hyperlinks/menus/atlaskit/PanelTextInput.d.ts +0 -39
- package/types/src/extensions/Hyperlinks/menus/atlaskit/PanelTextInputStyles.d.ts +0 -1
- package/types/src/extensions/Hyperlinks/menus/atlaskit/ToolbarComponent.d.ts +0 -11
- package/types/src/extensions/Hyperlinks/menus/helpers/PanelTextInput.d.ts +0 -39
- package/types/src/extensions/Hyperlinks/menus/helpers/PanelTextInputStyles.d.ts +0 -3
- package/types/src/extensions/Hyperlinks/menus/helpers/ToolbarComponent.d.ts +0 -13
- package/types/src/extensions/helpers/formatKeyboardShortcut.d.ts +0 -1
- package/types/src/lib/atlaskit/browser.d.ts +0 -12
- package/types/src/nodes/ChildgroupNode.d.ts +0 -28
- package/types/src/nodes/patchNodes.d.ts +0 -1
- package/types/src/plugins/TreeViewPlugin/index.d.ts +0 -2
- package/types/src/plugins/animation.d.ts +0 -2
- package/types/src/react/BlockNoteComposer.d.ts +0 -17
- package/types/src/react/BlockNotePlugin.d.ts +0 -1
- package/types/src/react/index.d.ts +0 -3
- package/types/src/react/useBlockNoteSetup.d.ts +0 -2
- package/types/src/registerBlockNote.d.ts +0 -2
- package/types/src/shared/components/toolbar/SimpleToolbarButton.d.ts +0 -15
- package/types/src/shared/components/toolbar/SimpleToolbarDropdown.d.ts +0 -11
- package/types/src/shared/components/toolbar/SimpleToolbarDropdownItem.d.ts +0 -11
- package/types/src/shared/components/toolbar/Toolbar.d.ts +0 -4
- package/types/src/shared/components/toolbar/ToolbarButton.d.ts +0 -15
- package/types/src/shared/components/toolbar/ToolbarDropdown.d.ts +0 -17
- package/types/src/shared/components/toolbar/ToolbarDropdownItem.d.ts +0 -11
- package/types/src/shared/components/toolbar/ToolbarDropdownTarget.d.ts +0 -8
- package/types/src/shared/components/toolbar/ToolbarSeparator.d.ts +0 -2
- package/types/src/shared/components/tooltip/TooltipContent.d.ts +0 -15
- package/types/src/shared/hooks/useEditorForceUpdate.d.ts +0 -2
- package/types/src/shared/plugins/suggestion/SuggestionListReactRenderer.d.ts +0 -71
- package/types/src/shared/plugins/suggestion/components/SuggestionGroup.d.ts +0 -23
- package/types/src/shared/plugins/suggestion/components/SuggestionGroupItem.d.ts +0 -9
- package/types/src/shared/plugins/suggestion/components/SuggestionList.d.ts +0 -11
- package/types/src/themes/BlockNoteEditorTheme.d.ts +0 -11
- package/types/src/useEditor.d.ts +0 -11
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { Menu } from "@mantine/core";
|
|
2
|
-
import { IconType } from "react-icons";
|
|
3
|
-
import { TiTick } from "react-icons/ti";
|
|
4
|
-
import { MouseEvent } from "react";
|
|
5
|
-
|
|
6
|
-
export type ToolbarDropdownItemProps = {
|
|
7
|
-
onClick?: (e: MouseEvent) => void;
|
|
8
|
-
text: string;
|
|
9
|
-
icon?: IconType;
|
|
10
|
-
isSelected?: boolean;
|
|
11
|
-
children?: any;
|
|
12
|
-
isDisabled?: boolean;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export function ToolbarDropdownItem(props: ToolbarDropdownItemProps) {
|
|
16
|
-
const ItemIcon = props.icon;
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<Menu.Item
|
|
20
|
-
key={props.text}
|
|
21
|
-
onClick={props.onClick}
|
|
22
|
-
icon={ItemIcon && <ItemIcon size={16} />}
|
|
23
|
-
rightSection={
|
|
24
|
-
props.isSelected ? (
|
|
25
|
-
<TiTick size={16} />
|
|
26
|
-
) : (
|
|
27
|
-
// Ensures space for tick even if item isn't currently selected.
|
|
28
|
-
<div style={{ width: "16px", padding: "0" }} />
|
|
29
|
-
)
|
|
30
|
-
}
|
|
31
|
-
disabled={props.isDisabled}>
|
|
32
|
-
{props.text}
|
|
33
|
-
</Menu.Item>
|
|
34
|
-
);
|
|
35
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { Button } from "@mantine/core";
|
|
2
|
-
import { HiChevronDown } from "react-icons/hi";
|
|
3
|
-
import { IconType } from "react-icons";
|
|
4
|
-
import { forwardRef } from "react";
|
|
5
|
-
|
|
6
|
-
export type ToolbarDropdownTargetProps = {
|
|
7
|
-
text: string;
|
|
8
|
-
icon?: IconType;
|
|
9
|
-
isDisabled?: boolean;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export const ToolbarDropdownTarget = forwardRef<
|
|
13
|
-
HTMLButtonElement,
|
|
14
|
-
ToolbarDropdownTargetProps
|
|
15
|
-
>((props: ToolbarDropdownTargetProps, ref) => {
|
|
16
|
-
const { text, icon, isDisabled, ...others } = props;
|
|
17
|
-
|
|
18
|
-
const TargetIcon = props.icon;
|
|
19
|
-
return (
|
|
20
|
-
<Button
|
|
21
|
-
leftIcon={TargetIcon && <TargetIcon size={16} />}
|
|
22
|
-
rightIcon={<HiChevronDown />}
|
|
23
|
-
size={"xs"}
|
|
24
|
-
variant={"subtle"}
|
|
25
|
-
disabled={props.isDisabled}
|
|
26
|
-
ref={ref}
|
|
27
|
-
{...others}>
|
|
28
|
-
{props.text}
|
|
29
|
-
</Button>
|
|
30
|
-
);
|
|
31
|
-
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
.tooltip {
|
|
2
|
-
color: var(--N40);
|
|
3
|
-
background-color: var(--N800);
|
|
4
|
-
box-shadow: 0 0 10px rgba(253, 254, 255, 0.8),
|
|
5
|
-
0 0 3px rgba(253, 254, 255, 0.4);
|
|
6
|
-
border-radius: 2px;
|
|
7
|
-
font-size: smaller;
|
|
8
|
-
text-align: center;
|
|
9
|
-
padding: 4px;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
.secondaryText {
|
|
13
|
-
font-weight: 400;
|
|
14
|
-
opacity: 0.6;
|
|
15
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import styles from "./TooltipContent.module.css";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Helper for the tooltip for inline bubble menu buttons.
|
|
5
|
-
*
|
|
6
|
-
* Often used to display a tooltip showing the command name + keyboard shortcut, e.g.:
|
|
7
|
-
*
|
|
8
|
-
* Bold
|
|
9
|
-
* Ctrl+B
|
|
10
|
-
*
|
|
11
|
-
* TODO: maybe use default Tippy styles instead?
|
|
12
|
-
*/
|
|
13
|
-
export const TooltipContent = (props: {
|
|
14
|
-
mainTooltip: string;
|
|
15
|
-
secondaryTooltip?: string;
|
|
16
|
-
}) => (
|
|
17
|
-
<div className={styles.tooltip}>
|
|
18
|
-
<div>{props.mainTooltip}</div>
|
|
19
|
-
{props.secondaryTooltip && (
|
|
20
|
-
<div className={styles.secondaryText}>{props.secondaryTooltip}</div>
|
|
21
|
-
)}
|
|
22
|
-
</div>
|
|
23
|
-
);
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { Editor } from "@tiptap/core";
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
3
|
-
|
|
4
|
-
function useForceUpdate() {
|
|
5
|
-
const [, setValue] = useState(0);
|
|
6
|
-
|
|
7
|
-
return () => setValue((value) => value + 1);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// This is a component that is similar to https://github.com/ueberdosis/tiptap/blob/main/packages/react/src/useEditor.ts
|
|
11
|
-
// Use it to rerender a component whenever a transaction happens in the editor
|
|
12
|
-
export const useEditorForceUpdate = (editor: Editor) => {
|
|
13
|
-
const forceUpdate = useForceUpdate();
|
|
14
|
-
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
const callback = () => {
|
|
17
|
-
requestAnimationFrame(() => {
|
|
18
|
-
requestAnimationFrame(() => {
|
|
19
|
-
forceUpdate();
|
|
20
|
-
});
|
|
21
|
-
});
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
editor.on("transaction", callback);
|
|
25
|
-
return () => {
|
|
26
|
-
editor.off("transaction", callback);
|
|
27
|
-
};
|
|
28
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
29
|
-
}, [editor]);
|
|
30
|
-
};
|
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
import { Editor as ReactEditor, ReactRenderer } from "@tiptap/react";
|
|
2
|
-
import { Editor } from "@tiptap/core";
|
|
3
|
-
import tippy, { Instance } from "tippy.js";
|
|
4
|
-
import SuggestionItem from "./SuggestionItem";
|
|
5
|
-
import {
|
|
6
|
-
SuggestionList,
|
|
7
|
-
SuggestionListProps,
|
|
8
|
-
} from "./components/SuggestionList";
|
|
9
|
-
import { BlockNoteTheme } from "../../../BlockNoteTheme";
|
|
10
|
-
import { MantineProvider } from "@mantine/core";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* The interface that each suggestion renderer should conform to.
|
|
14
|
-
*/
|
|
15
|
-
export interface SuggestionRenderer<T extends SuggestionItem> {
|
|
16
|
-
/**
|
|
17
|
-
* Disposes of the suggestion menu.
|
|
18
|
-
*/
|
|
19
|
-
onExit?: (props: SuggestionRendererProps<T>) => void;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Updates the suggestion menu.
|
|
23
|
-
*
|
|
24
|
-
* This function should be called when the renderer's `props` change,
|
|
25
|
-
* after `onStart` has been called.
|
|
26
|
-
*/
|
|
27
|
-
onUpdate?: (props: SuggestionRendererProps<T>) => void;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Creates and displays a new suggestion menu popup.
|
|
31
|
-
*/
|
|
32
|
-
onStart?: (props: SuggestionRendererProps<T>) => void;
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Function for handling key events
|
|
36
|
-
*/
|
|
37
|
-
onKeyDown?: (event: KeyboardEvent) => boolean;
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* The DOM Element representing the suggestion menu
|
|
41
|
-
*/
|
|
42
|
-
getComponent: () => Element | undefined;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export type SuggestionRendererProps<T extends SuggestionItem> = {
|
|
46
|
-
/**
|
|
47
|
-
* Object containing all suggestion items, grouped by their `groupName`.
|
|
48
|
-
*/
|
|
49
|
-
groups: {
|
|
50
|
-
[groupName: string]: T[];
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* The total number of suggestion-items.
|
|
55
|
-
*/
|
|
56
|
-
count: number;
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* This callback is executed whenever the user selects an item.
|
|
60
|
-
*
|
|
61
|
-
* @param item the selected item
|
|
62
|
-
*/
|
|
63
|
-
onSelectItem: (item: T) => void;
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* A function returning the client rect to use as reference for positioning the suggestion menu popup.
|
|
67
|
-
*/
|
|
68
|
-
clientRect: (() => DOMRect) | null;
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* This callback is executed when the suggestion menu needs to be closed,
|
|
72
|
-
* e.g. when the user presses escape.
|
|
73
|
-
*/
|
|
74
|
-
onClose: () => void;
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* This function creates a SuggestionRenderer based on TipTap's ReactRenderer utility.
|
|
79
|
-
*
|
|
80
|
-
* The resulting renderer can be used to display a suggestion menu containing (grouped) suggestion items.
|
|
81
|
-
*
|
|
82
|
-
* This renderer also takes care of the following key events:
|
|
83
|
-
* - Key up/down, for navigating the suggestion menu (selecting different items)
|
|
84
|
-
* - Enter for picking the currently selected item and closing the menu
|
|
85
|
-
* - Escape to close the menu, without taking action
|
|
86
|
-
*
|
|
87
|
-
* @param editor the TipTap editor
|
|
88
|
-
* @returns the newly constructed SuggestionRenderer
|
|
89
|
-
*/
|
|
90
|
-
export default function createRenderer<T extends SuggestionItem>(
|
|
91
|
-
editor: Editor
|
|
92
|
-
): SuggestionRenderer<T> {
|
|
93
|
-
let component: ReactRenderer;
|
|
94
|
-
let popup: Instance[];
|
|
95
|
-
let componentsDisposedOrDisposing = true;
|
|
96
|
-
let selectedIndex = 0;
|
|
97
|
-
let props: SuggestionRendererProps<T> | undefined;
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Helper function to find out what item corresponds to a certain index.
|
|
101
|
-
*
|
|
102
|
-
* This function might throw an error if the index is invalid,
|
|
103
|
-
* or when this function is not called in the proper environment.
|
|
104
|
-
*
|
|
105
|
-
* @param index the index
|
|
106
|
-
* @returns the item that corresponds to the index
|
|
107
|
-
*/
|
|
108
|
-
const itemByIndex = (index: number): T => {
|
|
109
|
-
if (!props) {
|
|
110
|
-
throw new Error("props not set");
|
|
111
|
-
}
|
|
112
|
-
let currentIndex = 0;
|
|
113
|
-
for (const groupName in props.groups) {
|
|
114
|
-
const items = props.groups[groupName];
|
|
115
|
-
const groupSize = items.length;
|
|
116
|
-
// Check if index lies within this group
|
|
117
|
-
if (index < currentIndex + groupSize) {
|
|
118
|
-
return items[index - currentIndex];
|
|
119
|
-
}
|
|
120
|
-
currentIndex += groupSize;
|
|
121
|
-
}
|
|
122
|
-
throw Error("item not found");
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
return {
|
|
126
|
-
getComponent: () => {
|
|
127
|
-
if (!popup || !popup[0]) {
|
|
128
|
-
return undefined;
|
|
129
|
-
}
|
|
130
|
-
// return the tippy container element, this is used to ensure
|
|
131
|
-
// that click events inside the menu are handled properly.
|
|
132
|
-
return popup[0].reference;
|
|
133
|
-
},
|
|
134
|
-
onStart: (newProps) => {
|
|
135
|
-
props = newProps;
|
|
136
|
-
componentsDisposedOrDisposing = false;
|
|
137
|
-
selectedIndex = 0;
|
|
138
|
-
const componentProps: SuggestionListProps<T> = {
|
|
139
|
-
groups: newProps.groups,
|
|
140
|
-
count: newProps.count,
|
|
141
|
-
onSelectItem: newProps.onSelectItem,
|
|
142
|
-
selectedIndex,
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
component = new ReactRenderer(
|
|
146
|
-
(props: SuggestionListProps<T>) => (
|
|
147
|
-
<MantineProvider theme={BlockNoteTheme}>
|
|
148
|
-
<SuggestionList {...props} />
|
|
149
|
-
</MantineProvider>
|
|
150
|
-
),
|
|
151
|
-
{
|
|
152
|
-
editor: editor as ReactEditor,
|
|
153
|
-
props: componentProps,
|
|
154
|
-
}
|
|
155
|
-
);
|
|
156
|
-
|
|
157
|
-
popup = tippy("body", {
|
|
158
|
-
getReferenceClientRect: newProps.clientRect,
|
|
159
|
-
appendTo: () => document.body,
|
|
160
|
-
content: component.element,
|
|
161
|
-
showOnCreate: true,
|
|
162
|
-
interactive: true,
|
|
163
|
-
trigger: "manual",
|
|
164
|
-
placement: "bottom-start",
|
|
165
|
-
});
|
|
166
|
-
},
|
|
167
|
-
|
|
168
|
-
onUpdate: (newProps) => {
|
|
169
|
-
props = newProps;
|
|
170
|
-
if (props.groups !== component.props.groups) {
|
|
171
|
-
// if the set of items is different (e.g.: by typing / searching), reset the selectedIndex to 0
|
|
172
|
-
selectedIndex = 0;
|
|
173
|
-
}
|
|
174
|
-
const componentProps: SuggestionListProps<T> = {
|
|
175
|
-
groups: props.groups,
|
|
176
|
-
count: props.count,
|
|
177
|
-
onSelectItem: props.onSelectItem,
|
|
178
|
-
selectedIndex,
|
|
179
|
-
};
|
|
180
|
-
component.updateProps(componentProps);
|
|
181
|
-
|
|
182
|
-
popup[0].setProps({
|
|
183
|
-
getReferenceClientRect: props.clientRect,
|
|
184
|
-
});
|
|
185
|
-
},
|
|
186
|
-
|
|
187
|
-
onKeyDown: (event) => {
|
|
188
|
-
if (!props) {
|
|
189
|
-
return false;
|
|
190
|
-
}
|
|
191
|
-
if (event.key === "ArrowUp") {
|
|
192
|
-
selectedIndex = (selectedIndex + props.count - 1) % props.count;
|
|
193
|
-
component.updateProps({
|
|
194
|
-
selectedIndex,
|
|
195
|
-
});
|
|
196
|
-
return true;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
if (event.key === "ArrowDown") {
|
|
200
|
-
selectedIndex = (selectedIndex + 1) % props.count;
|
|
201
|
-
component.updateProps({
|
|
202
|
-
selectedIndex,
|
|
203
|
-
});
|
|
204
|
-
return true;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if (event.key === "Enter") {
|
|
208
|
-
const item = itemByIndex(selectedIndex);
|
|
209
|
-
props.onSelectItem(item);
|
|
210
|
-
return true;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
if (event.key === "Escape") {
|
|
214
|
-
props.onClose();
|
|
215
|
-
return true;
|
|
216
|
-
}
|
|
217
|
-
return false;
|
|
218
|
-
},
|
|
219
|
-
|
|
220
|
-
onExit: (_props) => {
|
|
221
|
-
if (componentsDisposedOrDisposing) {
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
// onExit, first hide tippy popup so it shows fade-out
|
|
225
|
-
// then (after 1 second, actually destroy resources)
|
|
226
|
-
componentsDisposedOrDisposing = true;
|
|
227
|
-
const popupToDestroy = popup[0];
|
|
228
|
-
const componentToDestroy = component;
|
|
229
|
-
popupToDestroy.hide();
|
|
230
|
-
setTimeout(() => {
|
|
231
|
-
popupToDestroy.destroy();
|
|
232
|
-
componentToDestroy.destroy();
|
|
233
|
-
}, 1000);
|
|
234
|
-
},
|
|
235
|
-
};
|
|
236
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { Menu } from "@mantine/core";
|
|
2
|
-
import SuggestionItem from "../SuggestionItem";
|
|
3
|
-
import { SuggestionGroupItem } from "./SuggestionGroupItem";
|
|
4
|
-
|
|
5
|
-
type SuggestionGroupProps<T> = {
|
|
6
|
-
/**
|
|
7
|
-
* Name of the group
|
|
8
|
-
*/
|
|
9
|
-
name: string;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* The list of items
|
|
13
|
-
*/
|
|
14
|
-
items: T[];
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Index of the selected item in this group; relative to this item group (so 0 refers to the first item in this group)
|
|
18
|
-
* This should be 'undefined' if none of the items in this group are selected
|
|
19
|
-
*/
|
|
20
|
-
selectedIndex?: number;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Callback that gets executed when an item is clicked on.
|
|
24
|
-
*/
|
|
25
|
-
clickItem: (item: T) => void;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export function SuggestionGroup<T extends SuggestionItem>(
|
|
29
|
-
props: SuggestionGroupProps<T>
|
|
30
|
-
) {
|
|
31
|
-
return (
|
|
32
|
-
<>
|
|
33
|
-
<Menu.Label>{props.name}</Menu.Label>
|
|
34
|
-
{props.items.map((item, index) => {
|
|
35
|
-
return (
|
|
36
|
-
<SuggestionGroupItem
|
|
37
|
-
item={item}
|
|
38
|
-
key={index} // TODO: using index as key is not ideal for performance, better have ids on suggestionItems
|
|
39
|
-
index={index}
|
|
40
|
-
selectedIndex={props.selectedIndex}
|
|
41
|
-
clickItem={props.clickItem}
|
|
42
|
-
/>
|
|
43
|
-
);
|
|
44
|
-
})}
|
|
45
|
-
</>
|
|
46
|
-
);
|
|
47
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import SuggestionItem from "../SuggestionItem";
|
|
2
|
-
import { useEffect, useRef } from "react";
|
|
3
|
-
import { Badge, createStyles, Menu, Stack, Text } from "@mantine/core";
|
|
4
|
-
|
|
5
|
-
const MIN_LEFT_MARGIN = 5;
|
|
6
|
-
|
|
7
|
-
export type SuggestionGroupItemProps<T> = {
|
|
8
|
-
item: T;
|
|
9
|
-
index: number;
|
|
10
|
-
selectedIndex?: number;
|
|
11
|
-
clickItem: (item: T) => void;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export function SuggestionGroupItem<T extends SuggestionItem>(
|
|
15
|
-
props: SuggestionGroupItemProps<T>
|
|
16
|
-
) {
|
|
17
|
-
const itemRef = useRef<HTMLButtonElement>(null);
|
|
18
|
-
const { classes } = createStyles({ root: {} })(undefined, {
|
|
19
|
-
name: "SuggestionListItem",
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
function isSelected() {
|
|
23
|
-
const isKeyboardSelected =
|
|
24
|
-
props.selectedIndex !== undefined && props.selectedIndex === props.index;
|
|
25
|
-
const isMouseSelected = itemRef.current?.matches(":hover");
|
|
26
|
-
|
|
27
|
-
return isKeyboardSelected || isMouseSelected;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Updates HTML "data-hovered" attribute which Mantine uses to set mouse hover styles.
|
|
31
|
-
// Allows users to "hover" menu items when navigating using the keyboard.
|
|
32
|
-
function updateSelection() {
|
|
33
|
-
isSelected()
|
|
34
|
-
? itemRef.current?.setAttribute("data-hovered", "true")
|
|
35
|
-
: itemRef.current?.removeAttribute("data-hovered");
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
// Updates whether the item is selected with the keyboard (triggered on selectedIndex prop change).
|
|
40
|
-
updateSelection();
|
|
41
|
-
|
|
42
|
-
if (
|
|
43
|
-
isSelected() &&
|
|
44
|
-
itemRef.current &&
|
|
45
|
-
itemRef.current.getBoundingClientRect().left > MIN_LEFT_MARGIN //TODO: Kinda hacky, fix
|
|
46
|
-
// This check is needed because initially the menu is initialized somewhere above outside the screen (with left = 1)
|
|
47
|
-
// scrollIntoView() is called before the menu is set in the right place, and without the check would scroll to the top of the page every time
|
|
48
|
-
) {
|
|
49
|
-
itemRef.current.scrollIntoView({
|
|
50
|
-
behavior: "smooth",
|
|
51
|
-
block: "nearest",
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
const Icon = props.item.icon;
|
|
57
|
-
|
|
58
|
-
return (
|
|
59
|
-
<Menu.Item
|
|
60
|
-
className={classes.root}
|
|
61
|
-
icon={Icon && <Icon size={18} />}
|
|
62
|
-
onClick={() => props.clickItem(props.item)}
|
|
63
|
-
// Ensures an item selected with both mouse & keyboard doesn't get deselected on mouse leave.
|
|
64
|
-
onMouseLeave={() => {
|
|
65
|
-
setTimeout(() => {
|
|
66
|
-
updateSelection();
|
|
67
|
-
});
|
|
68
|
-
}}
|
|
69
|
-
ref={itemRef}
|
|
70
|
-
rightSection={
|
|
71
|
-
props.item.shortcut && <Badge size={"xs"}>{props.item.shortcut}</Badge>
|
|
72
|
-
}>
|
|
73
|
-
<Stack>
|
|
74
|
-
{/*Might need separate classes.*/}
|
|
75
|
-
<Text size={14} weight={500}>
|
|
76
|
-
{props.item.name}
|
|
77
|
-
</Text>
|
|
78
|
-
<Text size={10}>{props.item.hint}</Text>
|
|
79
|
-
</Stack>
|
|
80
|
-
</Menu.Item>
|
|
81
|
-
);
|
|
82
|
-
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { createStyles, Menu } from "@mantine/core";
|
|
2
|
-
import { SuggestionGroup } from "./SuggestionGroup";
|
|
3
|
-
import SuggestionItem from "../SuggestionItem";
|
|
4
|
-
|
|
5
|
-
export type SuggestionListProps<T> = {
|
|
6
|
-
// Object containing all suggestion items, grouped by their `groupName`.
|
|
7
|
-
groups: {
|
|
8
|
-
[groupName: string]: T[];
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
//The total number of suggestion-items
|
|
12
|
-
count: number;
|
|
13
|
-
|
|
14
|
-
// This callback gets executed whenever an item is clicked on
|
|
15
|
-
onSelectItem: (item: T) => void;
|
|
16
|
-
|
|
17
|
-
// The index of the item that is currently selected (but not yet clicked on)
|
|
18
|
-
selectedIndex: number;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
// Stateless component that renders the suggestion list
|
|
22
|
-
export function SuggestionList<T extends SuggestionItem>(
|
|
23
|
-
props: SuggestionListProps<T>
|
|
24
|
-
) {
|
|
25
|
-
const { classes } = createStyles({ root: {} })(undefined, {
|
|
26
|
-
name: "SuggestionList",
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
const renderedGroups = [];
|
|
30
|
-
|
|
31
|
-
let currentGroupIndex = 0;
|
|
32
|
-
|
|
33
|
-
for (const groupName in props.groups) {
|
|
34
|
-
const items = props.groups[groupName];
|
|
35
|
-
|
|
36
|
-
renderedGroups.push(
|
|
37
|
-
<SuggestionGroup
|
|
38
|
-
key={groupName}
|
|
39
|
-
name={groupName}
|
|
40
|
-
items={items}
|
|
41
|
-
selectedIndex={
|
|
42
|
-
props.selectedIndex >= currentGroupIndex
|
|
43
|
-
? props.selectedIndex - currentGroupIndex
|
|
44
|
-
: undefined
|
|
45
|
-
}
|
|
46
|
-
clickItem={props.onSelectItem}></SuggestionGroup>
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
currentGroupIndex += items.length;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return (
|
|
53
|
-
<Menu
|
|
54
|
-
/** Hacky fix to get the desired menu behaviour. The trigger="hover"
|
|
55
|
-
* attribute allows focus to remain on the editor, allowing for suggestion
|
|
56
|
-
* filtering. The closeDelay=10000000 attribute allows the menu to stay open
|
|
57
|
-
* practically indefinitely, as normally hovering off it would cause it to
|
|
58
|
-
* close due to trigger="hover".
|
|
59
|
-
*/
|
|
60
|
-
defaultOpened={true}
|
|
61
|
-
trigger={"hover"}
|
|
62
|
-
closeDelay={10000000}>
|
|
63
|
-
<Menu.Dropdown className={classes.root}>
|
|
64
|
-
{renderedGroups.length > 0 ? (
|
|
65
|
-
renderedGroups
|
|
66
|
-
) : (
|
|
67
|
-
<Menu.Item>No match found</Menu.Item>
|
|
68
|
-
)}
|
|
69
|
-
</Menu.Dropdown>
|
|
70
|
-
</Menu>
|
|
71
|
-
|
|
72
|
-
// doesn't work well yet, maybe https://github.com/atomiks/tippyjs-react/issues/173
|
|
73
|
-
// We now render the tippy element manually in SuggestionListReactRenderer
|
|
74
|
-
// <Tippy
|
|
75
|
-
// visible={true}
|
|
76
|
-
// placement="bottom-start"
|
|
77
|
-
// content={
|
|
78
|
-
// <div className={styles.menuList}>
|
|
79
|
-
// <PopupMenuGroup maxWidth="250px" maxHeight="400px">
|
|
80
|
-
// {renderedGroups.length > 0 ? (
|
|
81
|
-
// renderedGroups
|
|
82
|
-
// ) : (
|
|
83
|
-
// <Section title={"No match found"}> </Section>
|
|
84
|
-
// )}
|
|
85
|
-
// </PopupMenuGroup>
|
|
86
|
-
// </div>
|
|
87
|
-
// }
|
|
88
|
-
// interactive={false}>
|
|
89
|
-
// <div></div>
|
|
90
|
-
// </Tippy>
|
|
91
|
-
);
|
|
92
|
-
}
|
package/src/useEditor.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { EditorOptions, useEditor as useEditorTiptap } from "@tiptap/react";
|
|
2
|
-
|
|
3
|
-
import { DependencyList } from "react";
|
|
4
|
-
import { getBlockNoteExtensions } from "./BlockNoteExtensions";
|
|
5
|
-
import styles from "./editor.module.css";
|
|
6
|
-
import rootStyles from "./root.module.css";
|
|
7
|
-
|
|
8
|
-
type BlockNoteEditorOptions = EditorOptions & {
|
|
9
|
-
enableBlockNoteExtensions: boolean;
|
|
10
|
-
disableHistoryExtension: boolean;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
const blockNoteExtensions = getBlockNoteExtensions();
|
|
14
|
-
|
|
15
|
-
const blockNoteOptions = {
|
|
16
|
-
enableInputRules: true,
|
|
17
|
-
enablePasteRules: true,
|
|
18
|
-
enableCoreExtensions: false,
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Main hook for importing a BlockNote editor into a react project
|
|
23
|
-
*/
|
|
24
|
-
export const useEditor = (
|
|
25
|
-
options: Partial<BlockNoteEditorOptions> = {},
|
|
26
|
-
deps: DependencyList = []
|
|
27
|
-
) => {
|
|
28
|
-
const extensions = options.disableHistoryExtension
|
|
29
|
-
? blockNoteExtensions.filter((e) => e.name !== "history")
|
|
30
|
-
: blockNoteExtensions;
|
|
31
|
-
|
|
32
|
-
const tiptapOptions = {
|
|
33
|
-
...blockNoteOptions,
|
|
34
|
-
...options,
|
|
35
|
-
extensions:
|
|
36
|
-
options.enableBlockNoteExtensions === false
|
|
37
|
-
? options.extensions
|
|
38
|
-
: [...(options.extensions || []), ...extensions],
|
|
39
|
-
editorProps: {
|
|
40
|
-
attributes: {
|
|
41
|
-
...(options.editorProps?.attributes || {}),
|
|
42
|
-
class: [
|
|
43
|
-
styles.bnEditor,
|
|
44
|
-
rootStyles.bnRoot,
|
|
45
|
-
(options.editorProps?.attributes as any)?.class || "",
|
|
46
|
-
].join(" "),
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
return useEditorTiptap(tiptapOptions, deps);
|
|
51
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { EditorContent } from "@tiptap/react";
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { Command } from "prosemirror-state";
|
|
2
|
-
/**
|
|
3
|
-
* Code taken from https://github.com/ProseMirror/prosemirror-commands/blob/97a8cb5fac25e697d4693ce343e2e3b020a7fa2f/src/commands.ts
|
|
4
|
-
* Reason for modification: https://github.com/YousefED/BlockNote/pull/11
|
|
5
|
-
*
|
|
6
|
-
* BlockA
|
|
7
|
-
* BlockB
|
|
8
|
-
* Order of behavior has been switched to make first and second blocks content
|
|
9
|
-
* merge before trying to add second block as child of first
|
|
10
|
-
*
|
|
11
|
-
* behavior responsible for joining BlockB as A child of BlockA moved to (line 379 - 393 original file) after
|
|
12
|
-
* behavior responsible for joining content of BlockA and BlockB (line 402 - 422 original file)
|
|
13
|
-
*/
|
|
14
|
-
export declare const joinBackward: Command;
|