diff --git a/packages/core/src/api/parsers/pasteExtension.ts b/packages/core/src/api/parsers/pasteExtension.ts index d594c50b7e..c9648e0878 100644 --- a/packages/core/src/api/parsers/pasteExtension.ts +++ b/packages/core/src/api/parsers/pasteExtension.ts @@ -27,6 +27,11 @@ export const createPasteFromClipboardExtension = < handleDOMEvents: { paste(_view, event) { event.preventDefault(); + + if (!editor.isEditable) { + return; + } + let format: (typeof acceptedMIMETypes)[number] | null = null; for (const mimeType of acceptedMIMETypes) { diff --git a/packages/core/src/editor/Block.css b/packages/core/src/editor/Block.css index 7c2d968894..0acce7449f 100644 --- a/packages/core/src/editor/Block.css +++ b/packages/core/src/editor/Block.css @@ -279,7 +279,6 @@ NESTED BLOCKS background-color: rgb(242, 241, 238); border-radius: 4px; color: rgb(125, 121, 122); - cursor: pointer; display: flex; flex-direction: row; gap: 10px; @@ -287,7 +286,7 @@ NESTED BLOCKS width: 100%; } -[data-file-block] .bn-add-file-button:hover { +.bn-editor[contenteditable="true"] [data-file-block] .bn-add-file-button:hover { background-color: rgb(225, 225, 225); } diff --git a/packages/core/src/editor/BlockNoteEditor.ts b/packages/core/src/editor/BlockNoteEditor.ts index 53ec4d9f83..9ee69652ee 100644 --- a/packages/core/src/editor/BlockNoteEditor.ts +++ b/packages/core/src/editor/BlockNoteEditor.ts @@ -194,11 +194,7 @@ export class BlockNoteEditor< ISchema, SSchema >; - public readonly filePanel?: FilePanelProsemirrorPlugin< - BSchema, - ISchema, - SSchema - >; + public readonly filePanel?: FilePanelProsemirrorPlugin; public readonly tableHandles?: TableHandlesProsemirrorPlugin< ISchema, SSchema diff --git a/packages/core/src/extensions/FilePanel/FilePanelPlugin.ts b/packages/core/src/extensions/FilePanel/FilePanelPlugin.ts index 35a4c1d640..7b6bda4005 100644 --- a/packages/core/src/extensions/FilePanel/FilePanelPlugin.ts +++ b/packages/core/src/extensions/FilePanel/FilePanelPlugin.ts @@ -5,7 +5,6 @@ import type { BlockNoteEditor } from "../../editor/BlockNoteEditor"; import { UiElementPosition } from "../../extensions-shared/UiElementPosition"; import type { BlockFromConfig, - BlockSchema, FileBlockConfig, InlineContentSchema, StyleSchema, @@ -26,9 +25,12 @@ export class FilePanelView public state?: FilePanelState; public emitUpdate: () => void; - public prevWasEditable: boolean | null = null; - constructor( + private readonly editor: BlockNoteEditor< + Record, + I, + S + >, private readonly pluginKey: PluginKey, private readonly pmView: EditorView, emitUpdate: (state: FilePanelState) => void @@ -79,7 +81,7 @@ export class FilePanelView block: BlockFromConfig; } = this.pluginKey.getState(view.state); - if (!this.state?.show && pluginState.block) { + if (!this.state?.show && pluginState.block && this.editor.isEditable) { const blockElement = document.querySelector( `[data-node-type="blockContainer"][data-id="${pluginState.block.id}"]` )!; @@ -97,7 +99,8 @@ export class FilePanelView if ( !view.state.selection.eq(prevState.selection) || - !view.state.doc.eq(prevState.doc) + !view.state.doc.eq(prevState.doc) || + !this.editor.isEditable ) { if (this.state?.show) { this.state.show = false; @@ -126,22 +129,21 @@ export class FilePanelView const filePanelPluginKey = new PluginKey("FilePanelPlugin"); export class FilePanelProsemirrorPlugin< - B extends BlockSchema, I extends InlineContentSchema, S extends StyleSchema > extends EventEmitter { private view: FilePanelView | undefined; public readonly plugin: Plugin; - constructor(_editor: BlockNoteEditor) { + constructor(editor: BlockNoteEditor, I, S>) { super(); this.plugin = new Plugin<{ block: BlockFromConfig | undefined; }>({ key: filePanelPluginKey, view: (editorView) => { - this.view = new FilePanelView( - // editor, + this.view = new FilePanelView( + editor, filePanelPluginKey, editorView, (state) => { diff --git a/packages/core/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts b/packages/core/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts index 25114a64f7..63f096304a 100644 --- a/packages/core/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +++ b/packages/core/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts @@ -15,7 +15,6 @@ export class FormattingToolbarView implements PluginView { public preventHide = false; public preventShow = false; - public prevWasEditable: boolean | null = null; public shouldShow: (props: { view: EditorView; @@ -93,16 +92,10 @@ export class FormattingToolbarView implements PluginView { const isSame = oldState && oldState.doc.eq(doc) && oldState.selection.eq(selection); - if ( - (this.prevWasEditable === null || - this.prevWasEditable === this.editor.isEditable) && - (composing || isSame) - ) { + if (composing || isSame) { return; } - this.prevWasEditable = this.editor.isEditable; - // support for CellSelections const { ranges } = selection; const from = Math.min(...ranges.map((range) => range.$from.pos)); @@ -116,11 +109,12 @@ export class FormattingToolbarView implements PluginView { }); // Checks if menu should be shown/updated. - if ( - this.editor.isEditable && - !this.preventShow && - (shouldShow || this.preventHide) - ) { + if (!this.preventShow && (shouldShow || this.preventHide)) { + // Unlike other UI elements, we don't prevent the formatting toolbar from + // showing when the editor is not editable. This is because some buttons, + // e.g. the download file button, should still be accessible. Therefore, + // logic for hiding when the editor is non-editable is handled + // individually in each button. this.state = { show: true, referencePos: this.getSelectionBoundingBox(), diff --git a/packages/react/src/components/FormattingToolbar/DefaultButtons/BasicTextStyleButton.tsx b/packages/react/src/components/FormattingToolbar/DefaultButtons/BasicTextStyleButton.tsx index 7bd290efaf..1be42b3ee6 100644 --- a/packages/react/src/components/FormattingToolbar/DefaultButtons/BasicTextStyleButton.tsx +++ b/packages/react/src/components/FormattingToolbar/DefaultButtons/BasicTextStyleButton.tsx @@ -101,7 +101,7 @@ export const BasicTextStyleButton =