mirror of
https://github.com/docmost/docmost.git
synced 2026-08-28 01:07:08 +08:00
feat(editor-ext): block typing/paste from replacing a selected base embed
Add a ProseMirror plugin with handleTextInput and handlePaste that return true (handled, no-op) when the current selection is a NodeSelection of the base embed. Pairs with the existing Backspace/ Delete keyboard guard — between them the two accidental-deletion paths (focus + delete key, focus + type a character) are blocked. Other deletion routes still work: range selections covering the node, programmatic deletes, and so on. Pressing an arrow key deselects the node so the user can type elsewhere.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Node, mergeAttributes } from '@tiptap/core';
|
||||
import { NodeSelection } from '@tiptap/pm/state';
|
||||
import { EditorState, NodeSelection, Plugin } from '@tiptap/pm/state';
|
||||
|
||||
export interface BaseEmbedOptions {
|
||||
HTMLAttributes: Record<string, any>;
|
||||
@@ -62,11 +62,11 @@ export const BaseEmbed = Node.create<BaseEmbedOptions>({
|
||||
|
||||
addKeyboardShortcuts() {
|
||||
// Block Backspace / Delete when the base embed itself is the
|
||||
// current selection — that's the "click on the embed and hit
|
||||
// delete" accidental-delete path. Returning true tells TipTap
|
||||
// we've handled the key, preventing the default removal.
|
||||
// Other deletion paths (range selections covering the node,
|
||||
// programmatic transactions) still go through.
|
||||
// current selection — the "click on the embed and hit delete"
|
||||
// accidental-delete path. Returning true tells TipTap we've
|
||||
// handled the key, preventing the default removal. Range
|
||||
// selections covering the node and programmatic deletes still
|
||||
// work normally.
|
||||
const isThisNodeSelected = (): boolean => {
|
||||
const { selection } = this.editor.state;
|
||||
return (
|
||||
@@ -79,4 +79,28 @@ export const BaseEmbed = Node.create<BaseEmbedOptions>({
|
||||
Delete: () => isThisNodeSelected(),
|
||||
};
|
||||
},
|
||||
|
||||
addProseMirrorPlugins() {
|
||||
// Same idea as the Backspace/Delete shortcuts above, but for the
|
||||
// other accidental-delete path: when the embed is the selection,
|
||||
// a typed character or paste would replace the whole node. These
|
||||
// hooks return true (handled, no-op) so the node stays put. The
|
||||
// user can still press an arrow key to deselect and then type.
|
||||
const nodeName = this.name;
|
||||
const isThisNodeSelected = (state: EditorState): boolean => {
|
||||
const { selection } = state;
|
||||
return (
|
||||
selection instanceof NodeSelection &&
|
||||
selection.node.type.name === nodeName
|
||||
);
|
||||
};
|
||||
return [
|
||||
new Plugin({
|
||||
props: {
|
||||
handleTextInput: (view) => isThisNodeSelected(view.state),
|
||||
handlePaste: (view) => isThisNodeSelected(view.state),
|
||||
},
|
||||
}),
|
||||
];
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user