Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
113 commits
Select commit Hold shift + click to select a range
4d6e252
wip: better liveblocks support
YousefED Nov 14, 2024
dcd7c72
Merge remote-tracking branch 'origin/main' into feature/liveblocks-v2
YousefED Nov 18, 2024
c659253
misc fixes
YousefED Nov 18, 2024
a03d33f
misc
YousefED Nov 19, 2024
85521df
revert minimal
YousefED Nov 19, 2024
e43741a
simplify setup
YousefED Nov 20, 2024
e0c7f0f
update config
YousefED Nov 20, 2024
d747238
fix
YousefED Nov 20, 2024
6ce69ea
fix
YousefED Nov 20, 2024
a3028c1
markview
YousefED Dec 14, 2024
15c7520
cleanup
YousefED Dec 14, 2024
b8a8d49
Merge remote-tracking branch 'origin/main' into feature/liveblocks-v2
YousefED Jan 8, 2025
1b44296
wip
YousefED Jan 10, 2025
23275a0
wip
YousefED Jan 13, 2025
721a4e9
wip
YousefED Jan 14, 2025
e824c42
wip
YousefED Jan 15, 2025
f2d4bb8
misc
YousefED Jan 16, 2025
434eafa
add threadstore tests
YousefED Jan 16, 2025
9d35f72
document recommended auth rules
YousefED Jan 16, 2025
58ed7c0
resolve
YousefED Jan 16, 2025
b761e1e
basic userstore impl
YousefED Jan 16, 2025
5f52147
user auth
YousefED Jan 16, 2025
060708d
Big comments UX WIP
matthewlipski Jan 24, 2025
5c6f45b
Merge branch 'main' into feature/comments
matthewlipski Jan 28, 2025
16c6a7a
Merge branch 'main' into feature/comments
matthewlipski Jan 28, 2025
a5e07c0
Updated reactions UX
matthewlipski Jan 28, 2025
b42047f
change reaction implementation
YousefED Feb 10, 2025
43a1eb0
reactions improvements
YousefED Feb 10, 2025
306c335
small cleanup
YousefED Feb 10, 2025
99d9d21
cleanups + mark some todos
YousefED Feb 10, 2025
4501af4
comments
YousefED Feb 11, 2025
eadb49d
fix locales
YousefED Feb 11, 2025
b81bab0
Merge remote-tracking branch 'upstream/main' into feature/comments
YousefED Feb 11, 2025
9f40651
fix build
YousefED Feb 11, 2025
7ae2b7f
cleanup + sample
YousefED Feb 11, 2025
748a183
fix build
YousefED Feb 11, 2025
e93b53b
fix lint
YousefED Feb 11, 2025
be9dd46
disable liveblocks for now
YousefED Feb 11, 2025
3e93d1e
lint
YousefED Feb 11, 2025
40269a5
fix linkify warning + make toggle editable comment
YousefED Feb 11, 2025
62a8944
fix content reset bug
YousefED Feb 11, 2025
22fdde6
Implemented PR feedback
matthewlipski Feb 11, 2025
c293fdf
Merge remote-tracking branch 'origin/feature/comments' into feature/c…
matthewlipski Feb 11, 2025
c0d1bd5
fix placeholder
YousefED Feb 12, 2025
311881c
Merge branch 'feature/comments' of github.com:TypeCellOS/BlockNote in…
YousefED Feb 12, 2025
a71fc69
clean comment editor
YousefED Feb 12, 2025
4d498de
fix build
YousefED Feb 12, 2025
c5a6a0c
fix placeholders
YousefED Feb 12, 2025
3f7828d
- Adjusted comment spacing
matthewlipski Feb 13, 2025
d2c9f34
Implemented PR feedback
matthewlipski Feb 14, 2025
6df6886
fix build
YousefED Feb 14, 2025
5b7e3d4
implement TipTapThreadStore
YousefED Feb 14, 2025
3ef17e5
address feedback
YousefED Feb 14, 2025
db7d339
add comment
YousefED Feb 17, 2025
6067a2b
Merge remote-tracking branch 'origin/main' into feature/liveblocks-v2
YousefED Feb 17, 2025
298ba46
Merge branch 'feature/liveblocks-v2' into feature/comments
YousefED Feb 17, 2025
c007f84
wip
YousefED Feb 17, 2025
99c599c
Merge branch 'main' into feature/comments
YousefED Feb 18, 2025
c0c848a
add autofocus
YousefED Feb 18, 2025
9576cfe
Simplified tooltip + popover interaction
matthewlipski Feb 18, 2025
44b2dca
feat: ShadCN comments (#1445)
matthewlipski Feb 20, 2025
6c6b017
change reaction auth
YousefED Feb 20, 2025
97f1f0a
Merge branch 'feature/comments' of github.com:TypeCellOS/BlockNote in…
YousefED Feb 20, 2025
5decc46
make emoji optional
YousefED Feb 20, 2025
4cb7af0
fix bug
YousefED Feb 20, 2025
27a2523
Extracted reaction badge WIP
matthewlipski Feb 20, 2025
b27db16
Merge remote-tracking branch 'origin/feature/comments' into feature/c…
matthewlipski Feb 20, 2025
65dfc20
fix useUsers
YousefED Feb 20, 2025
2fe1052
Fixed formatting toolbar not showing up when editor is non-editable
matthewlipski Feb 20, 2025
e3291d0
Merge remote-tracking branch 'origin/feature/comments' into feature/c…
matthewlipski Feb 20, 2025
165a014
Fixed reaction badge tooltip line breaks and made leaving comment not…
matthewlipski Feb 20, 2025
807d8d1
Improved badge UX and made reactions hide when editing
matthewlipski Feb 20, 2025
e3e5867
Fixed new comments sometimes not being selectable
matthewlipski Feb 21, 2025
6bdbf15
remove unused files
YousefED Feb 21, 2025
d0b3f39
rest thread store
YousefED Feb 22, 2025
cfd94eb
fix copy/paste
YousefED Feb 22, 2025
ac6a17c
add shift
YousefED Feb 22, 2025
f200646
add docs
YousefED Feb 22, 2025
7c0746e
Merge remote-tracking branch 'origin/main' into feature/comments
YousefED Feb 22, 2025
4d293ef
update docs
YousefED Feb 22, 2025
f35a66a
revert liveblocks, will be separate PR
YousefED Feb 23, 2025
8d9d542
clean lockfile
YousefED Feb 23, 2025
0f1e019
fix some todos
YousefED Feb 23, 2025
490291f
adress number of comments
YousefED Feb 23, 2025
11d9ee6
address more comments
YousefED Feb 23, 2025
7d4b64e
address some comments
YousefED Feb 23, 2025
8ec3e50
clean commentsplugin
YousefED Feb 23, 2025
fa1e5a7
ForceSelectionVisible
YousefED Feb 23, 2025
f2f29e7
fix floatingcomposercontroller
YousefED Feb 23, 2025
e97985e
fix unit test
YousefED Feb 23, 2025
a4a90b8
close threads on esc
YousefED Feb 23, 2025
df1d6a0
Merge remote-tracking branch 'origin/main' into feature/comments
YousefED Feb 23, 2025
7b128dc
remove debugger
YousefED Feb 23, 2025
9ae74bd
small fix
YousefED Feb 24, 2025
953aefa
Fixed badge styles on docs
matthewlipski Feb 25, 2025
46101a0
Fixed badge click handler
matthewlipski Feb 25, 2025
ab00b5d
Added remaining UX fixes from Mantine to Ariakit/ShadCN
matthewlipski Feb 25, 2025
38a670d
Externalized strings
matthewlipski Feb 26, 2025
8d8ebec
Small styling fix
matthewlipski Feb 26, 2025
6744b26
Merge branch 'main' into feature/comments
matthewlipski Feb 26, 2025
a7a5656
Small styling fix
matthewlipski Feb 26, 2025
ebfb4da
Fix lint
matthewlipski Feb 26, 2025
9944ca7
Fixed side menu regression issue
matthewlipski Feb 26, 2025
30003d7
Implemented PR feedback
matthewlipski Feb 27, 2025
f1557b1
Implemented PR feedback
matthewlipski Feb 27, 2025
a647ec3
Updated emoji picker screenshots
matthewlipski Feb 28, 2025
065c74d
Revert "Updated emoji picker screenshots"
matthewlipski Feb 28, 2025
f26edd3
Merge branch 'main' into feature/comments
matthewlipski Feb 28, 2025
ae534b4
Updated `package-lock.json`
matthewlipski Feb 28, 2025
9a12826
Merge branch 'main' into feature/comments
matthewlipski Feb 28, 2025
828d13e
Fixed `no` locale
matthewlipski Feb 28, 2025
46836e5
Updated `package-lock.json`
matthewlipski Feb 28, 2025
641a6b8
Added temp test pass
matthewlipski Feb 28, 2025
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
49 changes: 25 additions & 24 deletions docs/pages/docs/editor-basics/setup.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,26 @@ function useCreateBlockNote(

type BlockNoteEditorOptions = {
animations?: boolean;
tabBehavior?: "prefer-navigate-ui" | "prefer-indent";
sideMenuDetection?: "viewport" | "editor";
resolveFileUrl?: (file: File) => Promise<string>;
resolveUsers?: (user: string) => Promise<UserInfo>;
collaboration?: CollaborationOptions;
comments?: CommentsConfig;
defaultStyles?: boolean;
dictionary?: Dictionary;
disableExtensions?: string[];
domAttributes?: Record<string, string>;
dropCursor?: (opts: {
editor: BlockNoteEditor;
color?: string | false;
width?: number;
class?: string;
}) => Plugin;
initialContent?: PartialBlock[];
resolveFileUrl: (url: string) => Promise<string>
schema?: BlockNoteSchema;
setIdAttribute?: boolean;
sideMenuDetection?: "viewport" | "editor";
tabBehavior?: "prefer-navigate-ui" | "prefer-indent"
trailingBlock?: boolean;
uploadFile?: (file: File) => Promise<string>;
};
```

Expand All @@ -36,6 +51,8 @@ The hook takes two optional parameters:

`collaboration`: Options for enabling real-time collaboration. See [Real-time Collaboration](/docs/advanced/real-time-collaboration) for more info.

`comments`: Configuration for the comments feature, requires a `threadStore`. See [Comments](/docs/collaboration/comments) for more.

`defaultStyles`: Whether to use the default font and reset the styles of `<p>`, `<li>`, `<h1>`, etc. elements that are used in BlockNote. Defaults to true if undefined.

`dictionary`: Provide strings for localization. See the [Localization / i18n example](/examples/basic/localization) and [Custom Placeholders](/examples/basic/custom-placeholder).
Expand All @@ -48,38 +65,22 @@ The hook takes two optional parameters:

`initialContent:` The content that should be in the editor when it's created, represented as an array of [Partial Blocks](/docs/manipulating-blocks#partial-blocks).

`resolveFileUrl:` An async function that fetches the download URL of a file from an initial URL.
`resolveFileUrl:` Function to resolve file URLs for display/download. Useful for creating authenticated URLs or implementing custom protocols.

`resolveUsers`: Function to resolve user information for comments. See [Comments](/docs/collaboration/comments) for more.

`schema`: The editor schema if you want to extend your editor with custom blocks, styles, or inline content [Custom Schemas](/docs/custom-schemas).

`setIdAttribute`: Whether to render an `id` HTML attribute on blocks as well as a `data-id` attribute. Defaults to `false`.

`sideMenuDetection`: Determines whether the mouse cursor position is locked to the editor bounding box for showing the [Block Side Menu](/docs/ui-components/side-menu) and block drag & drop. When set to `viewport`, the Side Menu will be shown next to the nearest block to the cursor, regardless of where it is in the viewport. Dropping blocks will also be locked to the editor bounding box. Otherwise, the Side Menu will only be shown when the cursor is within the editor bounds, and blocks can only be dropped when hovering the editor. In order to use multiple editors, must be set to `editor`. Defaults to `viewport`.

`tabBehavior`: Determines whether pressing the tab key should navigate the UI for keyboard accessibility or indent the current block. Defaults to `prefer-navigate-ui`.
`tabBehavior`: Determines whether pressing the tab key should navigate toolbars for keyboard accessibility. When set to `"prefer-navigate-ui`, the user can navigate toolbars using Tab. Pressing Escape re-focuses the editor, and Tab now indents blocks. `"prefer-indent"` causes Tab to always indent blocks. Defaults to `prefer-navigate-ui`.

`trailingBlock`: An option which user can pass with `false` value to disable the automatic creation of a trailing new block on the next line when the user types or edits any block. Defaults to `true` if undefined.

`uploadFile`: A function which handles file uploads and eventually returns the URL to the uploaded file. Used for [Image blocks](/docs/editor-basics/default-schema#image).

`tabBehavior`: How Tab key behaves with multiple blocks selected and toolbar open:

- `"prefer-navigate-ui"`: Focus moves to toolbar. User needs to press `Escape` to close toolbar before indenting blocks. Better for keyboard accessibility.
- `"prefer-indent"`: Indents blocks regardless of toolbar state. Cannot navigate toolbars with keyboard.
Defaults to `"prefer-navigate-ui"`.

`sideMenuDetection`: How the side menu detection works:

- `"viewport"`: Shows menu for block next to mouse cursor
- `"editor"`: Only shows when hovering editor or menu itself
Defaults to `"viewport"`.

`resolveFileUrl`: Function to resolve file URLs for display/download. Useful for creating authenticated URLs or implementing custom protocols.

`resolveUsers`: Function to resolve user information for comments. See [Comments](/docs/collaboration/comments) for more.

`comments`: Configuration for the comments feature, requires a `threadStore`. See [Comments](/docs/collaboration/comments) for more.

**deps:** Dependency array that's internally passed to `useMemo`. A new editor will only be created when this array changes.

<Callout type="info" emoji={"💡"}>
Expand Down
2 changes: 1 addition & 1 deletion examples/07-collaboration/01-partykit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ In this example, we use PartyKit to let multiple users collaborate on a single B

**Relevant Docs:**

- [PartyKit](/docs/advanced/real-time-collaboration#partykit)
- [Editor Setup](/docs/editor-basics/setup)
- [PartyKit](/docs/collaboration/real-time-collaboration#partykit)
2 changes: 1 addition & 1 deletion examples/07-collaboration/02-liveblocks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ In this example, we use Liveblocks to let multiple users collaborate on a single

**Relevant Docs:**

- [Liveblocks](/docs/advanced/real-time-collaboration#liveblocks)
- [Editor Setup](/docs/editor-basics/setup)
- [Liveblocks](/docs/collaboration/real-time-collaboration#liveblocks)
3 changes: 2 additions & 1 deletion examples/07-collaboration/03-y-sweet/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ In this example, we use Y-Sweet to let multiple users collaborate on a single Bl

**Relevant Docs:**

- [Y-Sweet on Jamsocket](https://docs.jamsocket.com/y-sweet/tutorials/blocknote)
- [Editor Setup](/docs/editor-basics/setup)
- [Real-time collaboration](/docs/collaboration/real-time-collaboration)
- [Y-Sweet on Jamsocket](https://docs.jamsocket.com/y-sweet/tutorials/blocknote)
12 changes: 11 additions & 1 deletion examples/07-collaboration/04-comments/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
# Comments & Threads

TODO
In this example, you can add comments to the document while collaborating with others. You can also pick user accounts with different permissions, as well as react to, reply to, and resolve existing comments.

**Try it out:** Click the "Add comment" button in the [Formatting Toolbar](/docs/ui-components/formatting-toolbar) to add a comment!

**Relevant Docs:**

- [Editor Setup](/docs/editor-basics/setup)
- [Real-time collaboration](/docs/collaboration/real-time-collaboration)
- [Y-Sweet on Jamsocket](https://docs.jamsocket.com/y-sweet/tutorials/blocknote)
- [Comments](/docs/collaboration/comments)

17 changes: 12 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion packages/ariakit/src/popover/Popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ export const Popover = (
) => {
const { children, opened, position, ...rest } = props;

// @ts-ignore TODO
assertEmpty(rest);

return (
Expand Down
3 changes: 2 additions & 1 deletion packages/ariakit/src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@

.bn-ak-toolbar {
height: fit-content;
overflow: visible;
overflow: scroll;
max-width: 100vw;
}

.bn-toolbar .bn-ak-button {
Expand Down
11 changes: 1 addition & 10 deletions packages/ariakit/src/toolbar/ToolbarButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,12 @@ export const ToolbarButton = forwardRef<HTMLButtonElement, ToolbarButtonProps>(
isDisabled,
onClick,
label,
variant,
...rest
} = props;

// false, because rest props can be added by ariakit when button is used as a trigger
// assertEmpty in this case is only used at typescript level, not runtime level

// TODO
// @ts-ignore
assertEmpty(rest, false);

return (
Expand All @@ -57,13 +55,6 @@ export const ToolbarButton = forwardRef<HTMLButtonElement, ToolbarButtonProps>(
onClick={onClick}
aria-pressed={isSelected}
data-selected={isSelected ? "true" : undefined}
data-test={
// @ts-ignore TODO
props.mainTooltip.slice(0, 1).toLowerCase() +
// @ts-ignore TODO
props.mainTooltip.replace(/\s+/g, "").slice(1)
}
// size={"xs"}
disabled={isDisabled || false}
ref={ref}
{...rest}>
Expand Down
9 changes: 8 additions & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@
"@types/emoji-mart": "^3.0.14",
"@types/hast": "^3.0.0",
"@types/uuid": "^8.3.4",
"@hocuspocus/provider": "^2.15.2",
"eslint": "^8.10.0",
"jsdom": "^25.0.1",
"prettier": "^2.7.1",
Expand All @@ -116,6 +115,14 @@
"vite-plugin-eslint": "^1.8.1",
"vitest": "^2.0.3"
},
"peerDependencies": {
"@hocuspocus/provider": "^2.15.2"
},
"peerDependenciesMeta": {
"hocuspocus/provider": {
"optional": true
}
},
"eslintConfig": {
"extends": [
"../../.eslintrc.js"
Expand Down
83 changes: 10 additions & 73 deletions packages/core/src/editor/BlockNoteEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,75 +125,6 @@ export type BlockNoteEditorOptions<
*/
animations?: boolean;

/**
* Disable internal extensions (based on keys / extension name)
*/
disableExtensions: string[];

/**
* A dictionary object containing translations for the editor.
*/
dictionary?: Dictionary & Record<string, any>;

/**
* @deprecated, provide placeholders via dictionary instead
*/
placeholders: Record<
string | "default" | "emptyDocument",
string | undefined
>;

/**
* An object containing attributes that should be added to HTML elements of the editor.
*
* @example { editor: { class: "my-editor-class" } }
*/
domAttributes: Partial<BlockNoteDOMAttributes>;

/**
* The content that should be in the editor when it's created, represented as an array of partial block objects.
*/
initialContent: PartialBlock<
NoInfer<BSchema>,
NoInfer<ISchema>,
NoInfer<SSchema>
>[];
/**
* Use default BlockNote font and reset the styles of <p> <li> <h1> elements etc., that are used in BlockNote.
*
* @default true
*/
defaultStyles: boolean;

schema: BlockNoteSchema<BSchema, ISchema, SSchema>;

/**
* The `uploadFile` method is what the editor uses when files need to be uploaded (for example when selecting an image to upload).
* This method should set when creating the editor as this is application-specific.
*
* `undefined` means the application doesn't support file uploads.
*
* @param file The file that should be uploaded.
* @returns The URL of the uploaded file OR an object containing props that should be set on the file block (such as an id)
*/
uploadFile: (
file: File,
blockId?: string
) => Promise<string | Record<string, any>>;

/**
* Resolve a URL of a file block to one that can be displayed or downloaded. This can be used for creating authenticated URL or
* implementing custom protocols / schemes
* @returns The URL that's
*/
resolveFileUrl: (url: string) => Promise<string>;

resolveUsers: (userIds: string[]) => Promise<User[]>;

// TODO: decide "comments" or "threads"?
comments: {
threadStore: ThreadStore;
};
/**
* When enabled, allows for collaboration between multiple users.
*/
Expand Down Expand Up @@ -226,6 +157,10 @@ export type BlockNoteEditorOptions<
showCursorLabels?: "always" | "activity";
};

comments: {
threadStore: ThreadStore;
};

/**
* Use default BlockNote font and reset the styles of <p> <li> <h1> elements etc., that are used in BlockNote.
*
Expand Down Expand Up @@ -285,6 +220,8 @@ export type BlockNoteEditorOptions<
*/
resolveFileUrl: (url: string) => Promise<string>;

resolveUsers: (userIds: string[]) => Promise<User[]>;

schema: BlockNoteSchema<BSchema, ISchema, SSchema>;

/**
Expand Down Expand Up @@ -1431,11 +1368,11 @@ export class BlockNoteEditor<
);
}

public get ForceSelectionVisible() {
return this.showSelectionPlugin.ForceSelectionVisible;
public getForceSelectionVisible() {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use a getter / setter for this? (like we do for "isEditable")?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@matthewlipski can you add a comment?

return this.showSelectionPlugin.getEnabled();
}

public set ForceSelectionVisible(forceSelectionVisible: boolean) {
this.showSelectionPlugin.ForceSelectionVisible = forceSelectionVisible;
public setForceSelectionVisible(forceSelectionVisible: boolean) {
this.showSelectionPlugin.setEnabled(forceSelectionVisible);
}
}
1 change: 1 addition & 0 deletions packages/core/src/extensions/Comments/CommentsPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export class CommentsPlugin extends EventEmitter<any> {
this.threadStore.subscribe(this.updateMarksFromThreads);
Comment on lines +145 to +147
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, we need an API for this


editor.onCreate(() => {
// Need to wait for TipTap editor state to be initialized
this.updateMarksFromThreads(this.threadStore.getThreads());
editor.onSelectionChange(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels weird to register this after the create hook, why not just register in the constructor separately?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It needs to access the TipTap state, and bc we init the comments plugin in the BlockNoteEditor constructor, the state is still undefined at that time. Will add a comment

if (this.pendingComment) {
Expand Down
Loading
Loading