Skip to content

feat: Mentions & custom suggestion menus #520

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 34 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
6f749fd
Added async slash menu items POC
matthewlipski Jan 10, 2024
3d82986
Fixed vanilla example
matthewlipski Jan 10, 2024
c30d98e
Small test fix
matthewlipski Jan 10, 2024
22691e5
Implemented PR feedback
matthewlipski Jan 12, 2024
01c793e
Improved performance
matthewlipski Jan 12, 2024
7b39927
Simplified how outdated queries are ignored/cancelled
matthewlipski Jan 15, 2024
570e4c2
small fixes
YousefED Jan 15, 2024
d5cb006
Added custom suggestion menus PoC
matthewlipski Jan 15, 2024
03126c5
Updated custom mentions example
matthewlipski Jan 15, 2024
93e1d4f
refactor: Mentions & custom suggestion menus (#534)
matthewlipski Feb 13, 2024
242d42b
Refactored how remaining UI elements (except table handles) are creat…
matthewlipski Feb 13, 2024
89de7ac
Merge branch 'main' into mentions-suggestions
YousefED Feb 14, 2024
9563d8e
remove file left after merge
YousefED Feb 14, 2024
2cece52
Merge remote-tracking branch 'TypeCellOS/main' into mentions-suggestions
YousefED Feb 14, 2024
e196d3f
Replaced `data`/`position` hooks with refactored general hooks
matthewlipski Feb 14, 2024
7f47e5a
Fixed vanilla example
matthewlipski Feb 14, 2024
3f29e90
Lint fix
matthewlipski Feb 14, 2024
c9661ac
Minor fixes
matthewlipski Feb 14, 2024
8edebd1
Refactored table handles
matthewlipski Feb 14, 2024
4b9eb9a
Merge branch 'mentions-suggestions' into ui-component-creation-refactor
matthewlipski Feb 14, 2024
546d255
clean getitems
YousefED Feb 14, 2024
55ad4c0
misc
YousefED Feb 14, 2024
ce78cc6
test
YousefED Feb 14, 2024
9d4dcbd
tests
YousefED Feb 14, 2024
398fc25
small fixes
YousefED Feb 14, 2024
9de5fd5
Merge remote-tracking branch 'TypeCellOS/ui-component-creation-refact…
YousefED Feb 15, 2024
e0a7c25
Implemented PR feedback
matthewlipski Feb 15, 2024
d686d7f
Merge branch 'ui-component-creation-refactor' into mentions-suggestio…
matthewlipski Feb 15, 2024
7580ff9
Small naming fix
matthewlipski Feb 15, 2024
e1e774e
Merge pull request #576 from TypeCellOS/ui-component-creation-refactor
YousefED Feb 15, 2024
081db98
Added vanilla default slash menu items
matthewlipski Feb 15, 2024
9017f05
address feedback
YousefED Feb 15, 2024
175352b
Merge pull request #579 from TypeCellOS/mentions-suggestions-getitems
YousefED Feb 15, 2024
94db329
Merge remote-tracking branch 'TypeCellOS/refactor/playground-nextjs' …
YousefED Feb 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/02-ui-components/custom-ui/ColorMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const colors = [

// Formatting Toolbar sub menu for changing text and background color
export const ColorMenu = (
props: FormattingToolbarProps & HTMLAttributes<HTMLDivElement>
props: FormattingToolbarProps<any> & HTMLAttributes<HTMLDivElement>
) => {
const { editor, className, ...rest } = props;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ type CustomFormattingToolbarState = {
backgroundColor: string;
};

export const CustomFormattingToolbar = (props: FormattingToolbarProps) => {
export const CustomFormattingToolbar = (props: FormattingToolbarProps<any>) => {
// Function to get the state of toolbar buttons (active/inactive)
const getState = (): CustomFormattingToolbarState => {
const block = props.editor.getTextCursorPosition().block;
Expand Down
4 changes: 2 additions & 2 deletions examples/02-ui-components/custom-ui/CustomSideMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { BlockNoteEditor } from "@blocknote/core";
import { SideMenuPositioner } from "@blocknote/react";
import { DefaultPositionedSideMenu } from "@blocknote/react";
import { RxDragHandleHorizontal } from "react-icons/rx";

export const CustomSideMenu = (props: { editor: BlockNoteEditor }) => (
<SideMenuPositioner
<DefaultPositionedSideMenu
editor={props.editor}
sideMenu={(props) => (
// Side menu consists of only a drag handle
Expand Down
145 changes: 73 additions & 72 deletions examples/02-ui-components/custom-ui/CustomSlashMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,83 +1,84 @@
import { BlockNoteEditor } from "@blocknote/core";
import { ReactSlashMenuItem, SlashMenuPositioner } from "@blocknote/react";
import {
RiH1,
RiH2,
RiH3,
RiListOrdered,
RiListUnordered,
RiText,
} from "react-icons/ri";
// import { ReactSlashMenuItem, SlashMenuPositioner } from "@blocknote/react";
// import {
// RiH1,
// RiH2,
// RiH3,
// RiListOrdered,
// RiListUnordered,
// RiText,
// } from "react-icons/ri";

// Icons for slash menu items
const icons = {
Paragraph: RiText,
Heading: RiH1,
"Heading 2": RiH2,
"Heading 3": RiH3,
"Numbered List": RiListOrdered,
"Bullet List": RiListUnordered,
};
// const icons = {
// Paragraph: RiText,
// Heading: RiH1,
// "Heading 2": RiH2,
// "Heading 3": RiH3,
// "Numbered List": RiListOrdered,
// "Bullet List": RiListUnordered,
// };

export const CustomSlashMenu = (props: { editor: BlockNoteEditor }) => {
const editor = props.editor;

return (
<SlashMenuPositioner
editor={editor}
slashMenu={(props) => {
// Sorts items by group
const groups: Record<string, ReactSlashMenuItem[]> = {};
for (const item of props.filteredItems) {
if (!groups[item.group]) {
groups[item.group] = [];
}
return <div>TODO</div>;
// TODO
// <SlashMenuPositioner
// editor={editor}
// slashMenu={(props) => {
// // Sorts items by group
// const groups: Record<string, ReactSlashMenuItem[]> = {};
// for (const item of props.filteredItems) {
// if (!groups[item.group]) {
// groups[item.group] = [];
// }

groups[item.group].push(item);
}
// groups[item.group].push(item);
// }

// If query matches no items, show "No matches" message
if (props.filteredItems.length === 0) {
return <div className={"slash-menu"}>No matches</div>;
}
// // If query matches no items, show "No matches" message
// if (props.filteredItems.length === 0) {
// return <div className={"slash-menu"}>No matches</div>;
// }

return (
<div className={"slash-menu"}>
{Object.entries(groups).map(([group, items]) => (
// Component for each group
<div key={group} className={"slash-menu-group"}>
{/*Group label*/}
<div className={"slash-menu-label"}>{group}</div>
{/*Group items*/}
<div className={"slash-menu-item-group"}>
{items.map((item) => {
const Icon =
item.name in icons
? icons[item.name as keyof typeof icons]
: "div";
return (
<button
key={item.name}
className={`slash-menu-item${
props.filteredItems.indexOf(item) ===
props.keyboardHoveredItemIndex
? " active"
: ""
}`}
onClick={() => {
item.execute(editor);
editor.focus();
}}>
<Icon />
</button>
);
})}
</div>
</div>
))}
</div>
);
}}
/>
);
// return (
// <div className={"slash-menu"}>
// {Object.entries(groups).map(([group, items]) => (
// // Component for each group
// <div key={group} className={"slash-menu-group"}>
// {/*Group label*/}
// <div className={"slash-menu-label"}>{group}</div>
// {/*Group items*/}
// <div className={"slash-menu-item-group"}>
// {items.map((item) => {
// const Icon =
// item.name in icons
// ? icons[item.name as keyof typeof icons]
// : "div";
// return (
// <button
// key={item.name}
// className={`slash-menu-item${
// props.filteredItems.indexOf(item) ===
// props.keyboardHoveredItemIndex
// ? " active"
// : ""
// }`}
// onClick={() => {
// item.execute(editor);
// editor.focus();
// }}>
// <Icon />
// </button>
// );
// })}
// </div>
// </div>
// ))}
// </div>
// );
// }}
// />
// );
};
2 changes: 1 addition & 1 deletion examples/02-ui-components/custom-ui/LinkMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { HTMLAttributes, useState } from "react";

// Formatting Toolbar sub menu for creating links
export const LinkMenu = (
props: FormattingToolbarProps & HTMLAttributes<HTMLDivElement>
props: FormattingToolbarProps<any> & HTMLAttributes<HTMLDivElement>
) => {
const { editor, className, ...rest } = props;

Expand Down
22 changes: 2 additions & 20 deletions examples/02-ui-components/formatting-toolbar-buttons/App.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,10 @@
import {
BlockNoteView,
FormattingToolbarPositioner,
HyperlinkToolbarPositioner,
SideMenuPositioner,
SlashMenuPositioner,
useBlockNote,
} from "@blocknote/react";
import { BlockNoteView, useBlockNote } from "@blocknote/react";
import "@blocknote/react/style.css";
import { CustomFormattingToolbar } from "./CustomFormattingToolbar";

export default function App() {
// Creates a new editor instance.
const editor = useBlockNote();

// Renders the editor instance.
return (
<BlockNoteView editor={editor}>
<FormattingToolbarPositioner
editor={editor}
formattingToolbar={CustomFormattingToolbar}
/>
<HyperlinkToolbarPositioner editor={editor} />
<SlashMenuPositioner editor={editor} />
<SideMenuPositioner editor={editor} />
</BlockNoteView>
);
return <BlockNoteView editor={editor}>{/* TODO */}</BlockNoteView>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from "@blocknote/react";
import { CustomButton } from "./CustomButton";

export function CustomFormattingToolbar(props: FormattingToolbarProps) {
export function CustomFormattingToolbar(props: FormattingToolbarProps<any>) {
return (
<Toolbar>
<BlockTypeDropdown {...props} />
Expand Down
14 changes: 3 additions & 11 deletions examples/02-ui-components/side-menu-buttons/App.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
import {
BlockNoteView,
FormattingToolbarPositioner,
HyperlinkToolbarPositioner,
SideMenuPositioner,
SlashMenuPositioner,
useBlockNote,
} from "@blocknote/react";
import { BlockNoteView, useBlockNote } from "@blocknote/react";
import "@blocknote/react/style.css";

import { CustomSideMenu } from "./CustomSideMenu";

export default function App() {
// Creates a new editor instance.
const editor = useBlockNote();

// Renders the editor instance.
return (
<BlockNoteView editor={editor}>
{/* TODO
<FormattingToolbarPositioner editor={editor} />
<HyperlinkToolbarPositioner editor={editor} />
<SlashMenuPositioner editor={editor} />
<SideMenuPositioner editor={editor} sideMenu={CustomSideMenu} />
<SideMenuPositioner editor={editor} sideMenu={CustomSideMenu} /> */}
</BlockNoteView>
);
}
19 changes: 5 additions & 14 deletions examples/02-ui-components/side-menu-drag-handle-items/App.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,23 @@
import {
BlockNoteView,
DefaultSideMenu,
FormattingToolbarPositioner,
HyperlinkToolbarPositioner,
SideMenuPositioner,
SlashMenuPositioner,
useBlockNote,
} from "@blocknote/react";
import { BlockNoteView, useBlockNote } from "@blocknote/react";
import "@blocknote/react/style.css";

import { CustomDragHandleMenu } from "./CustomDragHandleMenu";

export default function App() {
// Creates a new editor instance.
const editor = useBlockNote();

// Renders the editor instance.
return (
<BlockNoteView editor={editor}>
<FormattingToolbarPositioner editor={editor} />
{/* TODO */}
{/* <FormattingToolbarPositioner editor={editor} />
<HyperlinkToolbarPositioner editor={editor} />
<SlashMenuPositioner editor={editor} />
<SideMenuPositioner
editor={editor}
sideMenu={(props) => (
<DefaultSideMenu {...props} dragHandleMenu={CustomDragHandleMenu} />
)}
/>
)} */}
{/* /> */}
</BlockNoteView>
);
}
4 changes: 2 additions & 2 deletions examples/02-ui-components/slash-menu-items/App.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { BlockNoteView, useBlockNote } from "@blocknote/react";
import "@blocknote/react/style.css";

import { customSlashMenuItems } from "./CustomSlashMenuItems";
// import { customSlashMenuItems } from "./CustomSlashMenuItems";

export default function App() {
// Creates a new editor instance.
const editor = useBlockNote({
slashMenuItems: customSlashMenuItems,
// slashMenuItems: customSlashMenuItems, TODO
});

// Renders the editor instance.
Expand Down
11 changes: 6 additions & 5 deletions examples/02-ui-components/ui-elements-remove/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {
BlockNoteView,
FormattingToolbarPositioner,
HyperlinkToolbarPositioner,
ImageToolbarPositioner,
SlashMenuPositioner,
// FormattingToolbarPositioner,
// HyperlinkToolbarPositioner,
// ImageToolbarPositioner,
// SlashMenuPositioner,
useBlockNote,
} from "@blocknote/react";
import "@blocknote/react/style.css";
Expand All @@ -15,10 +15,11 @@ export default function App() {
// Renders the editor instance.
return (
<BlockNoteView editor={editor}>
{/* TODO
<FormattingToolbarPositioner editor={editor} />
<HyperlinkToolbarPositioner editor={editor} />
<SlashMenuPositioner editor={editor} />
<ImageToolbarPositioner editor={editor} />
<ImageToolbarPositioner editor={editor} /> */}
</BlockNoteView>
);
}
15 changes: 4 additions & 11 deletions examples/02-ui-components/ui-elements-replace/App.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
import {
BlockNoteView,
FormattingToolbarPositioner,
HyperlinkToolbarPositioner,
ImageToolbarPositioner,
SideMenuPositioner,
SlashMenuPositioner,
useBlockNote,
} from "@blocknote/react";
import { BlockNoteView, useBlockNote } from "@blocknote/react";
import "@blocknote/react/style.css";

export default function App() {
Expand All @@ -16,14 +8,15 @@ export default function App() {
// Renders the editor instance.
return (
<BlockNoteView editor={editor}>
<FormattingToolbarPositioner editor={editor} />
{/* TODO */}
{/* <FormattingToolbarPositioner editor={editor} />
<HyperlinkToolbarPositioner editor={editor} />
<SlashMenuPositioner editor={editor} />
<SideMenuPositioner
editor={editor}
sideMenu={() => <div className={"sideMenu"}>Side Menu</div>}
/>
<ImageToolbarPositioner editor={editor} />
<ImageToolbarPositioner editor={editor} /> */}
</BlockNoteView>
);
}
Loading