Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
57a3198
shows the emojis, keyboard navigation yet to be setup
hunxjunedo Jun 17, 2024
4890198
fixed lint and styled emoji picker
hunxjunedo Jun 17, 2024
9ace67d
added support for keyboard shortcuts, and cleanup
hunxjunedo Jun 17, 2024
9f122b4
add more reasonable color to emojiMenu
hunxjunedo Jun 17, 2024
5795d62
added emoji option to slashmenu
hunxjunedo Jun 18, 2024
02318b8
optimized emojipicker for slower network
hunxjunedo Jun 18, 2024
4da8fd7
finally made the emoji menu accessible through the slash menu
hunxjunedo Jun 19, 2024
6de43ab
cleanup and add comments
hunxjunedo Jun 19, 2024
15bf3df
add the appropriate typescript code, removed ts errors
hunxjunedo Jun 20, 2024
d7f248b
added dark mode, moved styles to css file
hunxjunedo Jun 26, 2024
b8d08ea
fixed lint
hunxjunedo Jun 26, 2024
9f0051a
resolve conflict
hunxjunedo Jun 26, 2024
6114681
Started refactor
matthewlipski Jun 28, 2024
1f19707
added the empji item to slash menu and setup onclick, only eng locale…
hunxjunedo Jun 28, 2024
1c0fd74
get the emoji.tsx to render the emoji inline
hunxjunedo Jun 28, 2024
1941739
add option to show or hide emoji suggestion menu
hunxjunedo Jun 28, 2024
873176b
added locales and fixed type issue
hunxjunedo Jun 28, 2024
e62f21c
generalize emojimenu component and move dependencies to react dir
hunxjunedo Jun 29, 2024
3fa4920
create a new dir inlineContent and retent at and structure it
hunxjunedo Jun 29, 2024
b0a2186
Added grid suggestion menu to component context + refactor
matthewlipski Jul 2, 2024
c75a5f6
Merge branch 'refs/heads/main' into hunxjunedo-main
matthewlipski Jul 2, 2024
da5ee45
Updated package lock
matthewlipski Jul 2, 2024
92358e2
Small fixes
matthewlipski Jul 2, 2024
5986300
unlink columns length from css, and a new prop gridCols
hunxjunedo Jul 3, 2024
449825d
More cleanup & implemented PR feedback
matthewlipski Jul 5, 2024
d82fb81
Change emojis to use text instead of custom IC & fixed styles
matthewlipski Jul 5, 2024
e72af9d
Added empty grid items and loaders
matthewlipski Jul 7, 2024
6446f22
Small fix
matthewlipski Jul 7, 2024
f0e776f
Added docs & small fixes
matthewlipski Jul 9, 2024
ff3f3b9
Small dep array fix
matthewlipski Jul 9, 2024
853b948
Implemented PR feedback
matthewlipski Jul 9, 2024
956045b
Added `openSuggestionMenu` docs
matthewlipski Jul 9, 2024
23f8e2d
Added e2e tests
matthewlipski Jul 9, 2024
fe625d5
Updated snapshots
matthewlipski Jul 9, 2024
3f030db
Fully split regular & grid suggestion menu code
matthewlipski Jul 10, 2024
9438dc9
Implemented remaining feedback and updated tests
matthewlipski Jul 10, 2024
8d5fc1d
Added `emojiPicker` to `BlockNoteViewProps` docs
matthewlipski Jul 10, 2024
5a882dd
Updated tests
matthewlipski Jul 10, 2024
d2cf8b1
Updated screenshots
matthewlipski Jul 10, 2024
0e29580
Updated docs
matthewlipski Jul 11, 2024
583e37f
Cleaned up merge
matthewlipski Jul 11, 2024
33ab57b
Added missing files
matthewlipski Jul 11, 2024
7a17b42
Small fix + regen files
matthewlipski Jul 11, 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
51 changes: 51 additions & 0 deletions docs/pages/docs/advanced/grid-suggestion-menus.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
title: Grid Suggestion Menus
description: In addition to displaying Suggestion Menus as stacks, BlockNote also supports displaying them as grids.
imageTitle: Grid Suggestion Menus
---

import { Example } from "@/components/example";

# Grid Suggestion Menus

Grid Suggestion Menus appear when the user enters a trigger character, and text after the character is used to filter the menu items.

Grid Suggestion Menus are similar to regular Suggestion Menus, but results are organized in a grid, and users can use all arrow keys (including left, right) on their keyboard to navigate the results.

## Emoji Picker

The Emoji Picker is a Grid Suggestion Menu that opens with the `:` character (or when selecting emoji item in the Slash Menu).

It only displays once the user types 2 non-whitespace characters a query, to minimize cases where the user only wants to enter the `:` character.

<img
style={{ maxWidth: "400px" }}
src="/img/screenshots/emoji_picker.png"
alt="image"
/>

### Changing Emoji Picker Columns

By default, the Emoji Picker is rendered with 10 columns, but you can change this to any amount. In the demo below, the Emoji Picker is changed to only display 5 columns.

<Example name="ui-components/suggestion-menus-emoji-picker-columns" />

Passing `emojiPicker={false}` to `BlockNoteView` tells BlockNote not to show the default Emoji Picker. Adding the `GridSuggestionMenuController` with `triggerCharacter={":"}` and `columns={5}` tells BlockNote to show one with 5 columns instead.

### Replacing the Emoji Picker Component

You can replace the React component used for the Emoji Picker with your own, as you can see in the demo below.

<Example name="ui-components/suggestion-menus-emoji-picker-component" />

Again, we add a `GridSuggestionMenuController` component with `triggerCharacter={":"}` and set `emojiPicker={false}` to replace the default Emoji Picker.

Now, we also pass a component to its `gridSuggestionMenuComponent` prop. The `gridSuggestionMenuComponent` we pass is responsible for rendering the filtered items. The `GridSuggestionMenuController` controls its position and visibility (below the trigger character), and it also determines which items should be shown. Since we don't specify which items to show (the `getItems` prop isn't defined), it will use the default items for a grid, which are the emojis.

## Creating additional Grid Suggestion Menus

You can add additional Grid Suggestion Menus to the editor, which can use any trigger character. The demo below adds an example Grid Suggestion Menu for mentions, where each item is the first character of the user's name, and opens with the `@` character.

<Example name="ui-components/suggestion-menus-grid-mentions" />

Changing the column count in the new Grid Suggestion Menu, or the component used to render it, is done the same way as for the [Emoji Picker](/docs/advanced/grid-suggestion-menus#emoji-picker). For more information about how the mentions elements work, see [Custom Inline Content](/docs/custom-schemas/custom-inline-content).
3 changes: 3 additions & 0 deletions docs/pages/docs/editor-basics/setup.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export type BlockNoteViewProps = {
linkToolbar?: boolean;
sideMenu?: boolean;
slashMenu?: boolean;
emojiPicker?: boolean;
filePanel?: boolean;
tableHandles?: boolean;
children?:
Expand All @@ -120,6 +121,8 @@ export type BlockNoteViewProps = {

`slashMenu`: Whether the [Slash Menu](/docs/ui-components/suggestion-menus#slash-menu) should be enabled.

`emojiPicker`: Whether the [Emoji Picker](/docs/ui-components/suggestion-menus#emoji-picker) should be enabled.

`filePanel`: Whether the File Toolbar should be enabled.

`tableHandles`: Whether the Table Handles should be enabled.
Expand Down
25 changes: 23 additions & 2 deletions docs/pages/docs/ui-components/suggestion-menus.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ Passing `slashMenu={false}` to `BlockNoteView` tells BlockNote not to show the d

`getItems` should return the items that need to be shown in the Slash Menu, based on a `query` entered by the user (anything the user types after the `triggerCharacter`).

### Replacing the Suggestion Menu Component
### Replacing the Slash Menu Component

You can replace the React component used for the Suggestion Menu with your own, as you can see in the demo below.
You can replace the React component used for the Slash Menu with your own, as you can see in the demo below.

<Example name="ui-components/suggestion-menus-slash-menu-component" />

Expand All @@ -48,3 +48,24 @@ You can add additional Suggestion Menus to the editor, which can use any trigger
<Example name="custom-schema/suggestion-menus-mentions" />

Changing the items in the new Suggestion Menu, or the component used to render it, is done the same way as for the [Slash Menu](/docs/ui-components/suggestion-menus#slash-menu). For more information about how the mentions elements work, see [Custom Inline Content](/docs/custom-schemas/custom-inline-content).

## Additional Features

BlockNote offers a few other features for working with Suggestion Menus which may fit your use case.

### Opening Suggestion Menus Programmatically

While suggestion menus are generally meant to be opened when the user presses a trigger character, you may also want to open them from code. To do this, you can use the following editor method:

```typescript
openSuggestionMenu(triggerCharacter: string): void;

// Usage
editor.openSuggestionMenu("/");
```

### Waiting for a Query

You may want to hold off displaying a Suggestion Menu unless you're certain that the user actually wants to open the menu and not just enter the trigger character. In this case, you should use the `minQueryLength` prop for `SuggestionMenuController`, which takes a number.

The number indicates how many characters the user query needs to have before the menu is shown. When greater than 0, it also prevents the menu from displaying if the user enters a space immediately after the trigger character.
Binary file added docs/public/img/screenshots/emoji_picker.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
display: flex;
flex-direction: column;
gap: 8px;
height: fit-content;
max-height: 100%;

overflow: auto;

padding: 8px;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"playground": true,
"docs": true,
"author": "yousefed",
"tags": [
"Intermediate",
"Blocks",
"UI Components",
"Suggestion Menus",
"Emoji Picker"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import "@blocknote/core/fonts/inter.css";
import {
GridSuggestionMenuController,
useCreateBlockNote,
} from "@blocknote/react";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";

export default function App() {
// Creates a new editor instance.
const editor = useCreateBlockNote({
initialContent: [
{
type: "paragraph",
content: "Welcome to this demo!",
},
{
type: "paragraph",
content: "Press the ':' key to open the Emoji Picker",
},
{
type: "paragraph",
content: "There are now 5 columns instead of 10",
},
{
type: "paragraph",
},
],
});

// Renders the editor instance.
return (
<BlockNoteView editor={editor} emojiPicker={false}>
<GridSuggestionMenuController
triggerCharacter={":"}
// Changes the Emoji Picker to only have 5 columns.
columns={5}
minQueryLength={2}
/>
</BlockNoteView>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Changing Emoji Picker Columns

In this example, we change the Emoji Picker to display 5 columns instead of 10.

**Try it out:** Press the ":" key to open the Emoji Picker!

**Relevant Docs:**

- [Changing Emoji Picker Columns](/docs/ui-components/suggestion-menus#changing-emoji-picker-columns)
- [Editor Setup](/docs/editor-basics/setup)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<html lang="en">
<head>
<script>
<!-- AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY -->
</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Changing Emoji Picker Columns</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./main.tsx"></script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "@blocknote/example-suggestion-menus-emoji-picker-columns",
"description": "AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY",
"private": true,
"version": "0.12.4",
"scripts": {
"start": "vite",
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"lint": "eslint . --max-warnings 0"
},
"dependencies": {
"@blocknote/core": "latest",
"@blocknote/react": "latest",
"@blocknote/ariakit": "latest",
"@blocknote/mantine": "latest",
"@blocknote/shadcn": "latest",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/react": "^18.0.25",
"@types/react-dom": "^18.0.9",
"@vitejs/plugin-react": "^4.0.4",
"eslint": "^8.10.0",
"vite": "^4.4.8"
},
"eslintConfig": {
"extends": [
"../../../.eslintrc.js"
]
},
"eslintIgnore": [
"dist"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"playground": true,
"docs": true,
"author": "yousefed",
"tags": [
"Intermediate",
"UI Components",
"Suggestion Menus",
"Emoji Picker",
"Appearance & Styling"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import "@blocknote/core/fonts/inter.css";
import {
DefaultReactGridSuggestionItem,
GridSuggestionMenuController,
GridSuggestionMenuProps,
useCreateBlockNote,
} from "@blocknote/react";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";

import "./styles.css";

// Custom component to replace the default Emoji Picker.
function CustomEmojiPicker(
props: GridSuggestionMenuProps<DefaultReactGridSuggestionItem>
) {
return (
<div
className={"emoji-picker"}
style={
{ gridTemplateColumns: `repeat(${props.columns || 1}, 1fr)` } as any
}>
{props.items.map((item, index) => (
<div
className={`emoji-picker-item${
props.selectedIndex === index ? " selected" : ""
}`}
onClick={() => {
props.onItemClick?.(item);
}}>
{item.icon}
</div>
))}
</div>
);
}

export default function App() {
// Creates a new editor instance.
const editor = useCreateBlockNote({
initialContent: [
{
type: "paragraph",
content: "Welcome to this demo!",
},
{
type: "paragraph",
content: "Press the ':' key to open the Emoji Picker",
},
{
type: "paragraph",
content: "It's been replaced with a custom component",
},
{
type: "paragraph",
},
],
});

// Renders the editor instance.
return (
<BlockNoteView editor={editor} emojiPicker={false}>
<GridSuggestionMenuController
triggerCharacter={":"}
gridSuggestionMenuComponent={CustomEmojiPicker}
columns={10}
minQueryLength={2}
/>
</BlockNoteView>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Replacing Emoji Picker Component

In this example, we replace the default Emoji Picker component with a basic custom one.

**Try it out:** Press the ":" key to see the new Emoji Picker!

**Relevant Docs:**

- [Replacing the Emoji Picker Component](/docs/ui-components/suggestion-menus#replacing-the-emoji-picker-component)
- [Editor Setup](/docs/editor-basics/setup)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<html lang="en">
<head>
<script>
<!-- AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY -->
</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Replacing Emoji Picker Component</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./main.tsx"></script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "@blocknote/example-suggestion-menus-emoji-picker-component",
"description": "AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY",
"private": true,
"version": "0.12.4",
"scripts": {
"start": "vite",
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"lint": "eslint . --max-warnings 0"
},
"dependencies": {
"@blocknote/core": "latest",
"@blocknote/react": "latest",
"@blocknote/ariakit": "latest",
"@blocknote/mantine": "latest",
"@blocknote/shadcn": "latest",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/react": "^18.0.25",
"@types/react-dom": "^18.0.9",
"@vitejs/plugin-react": "^4.0.4",
"eslint": "^8.10.0",
"vite": "^4.4.8"
},
"eslintConfig": {
"extends": [
"../../../.eslintrc.js"
]
},
"eslintIgnore": [
"dist"
]
}
Loading