Skip to content

Commit 23cbacc

Browse files
Editor Locking (#135)
* Added editor functions for getting & setting whether the editor is editable * Added editor option to lock editing * Changed `setEditable` to use a setter
1 parent 26cdeae commit 23cbacc

File tree

7 files changed

+52
-19
lines changed

7 files changed

+52
-19
lines changed

packages/core/src/BlockNoteEditor.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,14 @@ export type BlockNoteEditorOptions = {
6969
* A callback function that runs whenever the text cursor position changes.
7070
*/
7171
onTextCursorPositionChange: (editor: BlockNoteEditor) => void;
72+
/**
73+
* Locks the editor from being editable by the user if set to `false`.
74+
*/
75+
editable: boolean;
76+
/**
77+
* The content that should be in the editor when it's created, represented as an array of partial block objects.
78+
*/
7279
initialContent: PartialBlock[];
73-
7480
/**
7581
* Use default BlockNote font and reset the styles of <p> <li> <h1> elements etc., that are used in BlockNote.
7682
*
@@ -134,6 +140,7 @@ export class BlockNoteEditor {
134140
onSelectionUpdate: () => {
135141
options.onTextCursorPositionChange?.(this);
136142
},
143+
editable: options.editable === undefined ? true : options.editable,
137144
extensions:
138145
options.enableBlockNoteExtensions === false
139146
? options._tiptapOptions?.extensions
@@ -312,6 +319,22 @@ export class BlockNoteEditor {
312319
}
313320
}
314321

322+
/**
323+
* Checks if the editor is currently editable, or if it's locked.
324+
* @returns True if the editor is editable, false otherwise.
325+
*/
326+
public get isEditable(): boolean {
327+
return this._tiptapEditor.isEditable;
328+
}
329+
330+
/**
331+
* Makes the editor editable or locks it, depending on the argument passed.
332+
* @param editable True to make the editor editable, or false to lock it.
333+
*/
334+
public set isEditable(editable: boolean) {
335+
this._tiptapEditor.setEditable(editable);
336+
}
337+
315338
/**
316339
* Inserts new blocks into the editor. If a block's `id` is undefined, BlockNote generates one automatically. Throws an
317340
* error if the reference block could not be found.

packages/core/src/extensions/DraggableBlocks/DraggableBlocksPlugin.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ export class BlockMenuView {
384384
const block = getDraggableBlockFromCoords(coords, this.editor.view);
385385

386386
// Closes the menu if the mouse cursor is beyond the editor vertically.
387-
if (!block) {
387+
if (!block || !this.editor.isEditable) {
388388
if (this.menuOpen) {
389389
this.menuOpen = false;
390390
this.blockMenu.hide();
@@ -411,11 +411,13 @@ export class BlockMenuView {
411411
}
412412

413413
// Shows or updates elements.
414-
if (!this.menuOpen) {
415-
this.menuOpen = true;
416-
this.blockMenu.render(this.getDynamicParams(), true);
417-
} else {
418-
this.blockMenu.render(this.getDynamicParams(), false);
414+
if (this.editor.isEditable) {
415+
if (!this.menuOpen) {
416+
this.menuOpen = true;
417+
this.blockMenu.render(this.getDynamicParams(), true);
418+
} else {
419+
this.blockMenu.render(this.getDynamicParams(), false);
420+
}
419421
}
420422
};
421423

packages/core/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ export class FormattingToolbarView {
5050

5151
public toolbarIsOpen = false;
5252

53+
public prevWasEditable: boolean | null = null;
54+
5355
public shouldShow: Exclude<FormattingToolbarPluginProps["shouldShow"], null> =
5456
({ view, state, from, to }) => {
5557
const { doc, selection } = state;
@@ -134,10 +136,16 @@ export class FormattingToolbarView {
134136
const isSame =
135137
oldState && oldState.doc.eq(doc) && oldState.selection.eq(selection);
136138

137-
if (composing || isSame) {
139+
if (
140+
(this.prevWasEditable === null ||
141+
this.prevWasEditable === this.editor.isEditable) &&
142+
(composing || isSame)
143+
) {
138144
return;
139145
}
140146

147+
this.prevWasEditable = this.editor.isEditable;
148+
141149
// support for CellSelections
142150
const { ranges } = selection;
143151
const from = Math.min(...ranges.map((range) => range.$from.pos));
@@ -154,6 +162,7 @@ export class FormattingToolbarView {
154162

155163
// Checks if menu should be shown.
156164
if (
165+
this.editor.isEditable &&
157166
!this.toolbarIsOpen &&
158167
!this.preventShow &&
159168
(shouldShow || this.preventHide)
@@ -184,7 +193,7 @@ export class FormattingToolbarView {
184193
if (
185194
this.toolbarIsOpen &&
186195
!this.preventHide &&
187-
(!shouldShow || this.preventShow)
196+
(!shouldShow || this.preventShow || !this.editor.isEditable)
188197
) {
189198
this.formattingToolbar.hide();
190199
this.toolbarIsOpen = false;

packages/core/src/extensions/HyperlinkToolbar/HyperlinkToolbarPlugin.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ class HyperlinkToolbarView {
145145
this.hyperlinkMarkRange = this.keyboardHoveredHyperlinkMarkRange;
146146
}
147147

148-
if (this.hyperlinkMark) {
148+
if (this.hyperlinkMark && this.editor.isEditable) {
149149
this.getDynamicParams();
150150

151151
// Shows menu.
@@ -171,7 +171,7 @@ class HyperlinkToolbarView {
171171
}
172172

173173
// Hides menu.
174-
if (!this.hyperlinkMark && prevHyperlinkMark) {
174+
if (prevHyperlinkMark && (!this.hyperlinkMark || !this.editor.isEditable)) {
175175
this.hyperlinkToolbar.element?.removeEventListener(
176176
"mouseleave",
177177
this.startMenuUpdateTimer

packages/core/src/shared/plugins/suggestion/SuggestionPlugin.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ class SuggestionPluginView<T extends SuggestionItem> {
147147

148148
this.pluginState = stopped ? prev : next;
149149

150-
if (stopped) {
150+
if (stopped || !this.editor.isEditable) {
151151
this.suggestionsMenu.hide();
152152

153153
// Listener stops focus moving to the menu on click.
@@ -160,7 +160,7 @@ class SuggestionPluginView<T extends SuggestionItem> {
160160
this.suggestionsMenu.render(this.getDynamicParams(), false);
161161
}
162162

163-
if (started) {
163+
if (started && this.editor.isEditable) {
164164
this.suggestionsMenu.render(this.getDynamicParams(), true);
165165

166166
// Listener stops focus moving to the menu on click.

packages/website/docs/docs/converting-blocks.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,7 @@ export default function App() {
110110
// Creates a new editor instance.
111111
const editor: BlockNoteEditor | null = useBlockNote({
112112
// Makes the editor non-editable.
113-
_tiptapOptions: {
114-
editable: false,
115-
},
113+
editable: false
116114
})
117115

118116
useEffect(() => {
@@ -245,9 +243,7 @@ export default function App() {
245243
// Creates a new editor instance.
246244
const editor: BlockNoteEditor | null = useBlockNote({
247245
// Makes the editor non-editable.
248-
_tiptapOptions: {
249-
editable: false,
250-
},
246+
editable: false
251247
})
252248

253249
useEffect(() => {

packages/website/docs/docs/editor.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ There are a number of options that you can pass to `useBlockNote()`, which you c
88

99
```typescript
1010
export type BlockNoteEditorOptions = Partial<{
11+
editable: boolean;
1112
initialContent: PartialBlock[];
1213
editorDOMAttributes: Record<string, string>;
1314
onEditorReady: (editor: BlockNoteEditor) => void;
@@ -19,6 +20,8 @@ export type BlockNoteEditorOptions = Partial<{
1920
}>;
2021
```
2122

23+
`editable:` Locks the editor from being editable by the user if set to `false`. [Editor Functions](/docs/blocks#editor-functions) will still work.
24+
2225
`initialContent:` The content that should be in the editor when it's created, represented as an array of [partial block objects](/docs/manipulating-blocks#partial-blocks).
2326

2427
`editorDOMAttributes:` An object containing attributes that should be added to the editor's HTML element. For example, you can pass `{ class: "my-editor-class" }` to set a custom class name.

0 commit comments

Comments
 (0)