From 67badb7dd03c6d36d31b90689247553c0386d771 Mon Sep 17 00:00:00 2001 From: Jim Fisher Date: Tue, 19 Oct 2021 18:46:17 +0100 Subject: [PATCH] Allow typing at the end of an inline element (#4578) * Allow typing at the end of an inline This fixes https://github.com/ianstormtaylor/slate/issues/4524 Steps to reproduce the buggy behavior: * Create a page with an inline element, or go to https://codepen.io/jameshfisher/pen/xxrXvVO * Put the cursor at the end of the inline code element * Type something Expected behavior: If the cursor is at the end of an inline, text should be inserted at the end of the inline. Actual behavior: Slate moves the cursor outside the inline before inserting text. This current behavior is explicitly coded. I nevertheless claim that this is a bug, or at least a misfeature in core. My expected behavior comes from: * The fact that the cursor is inside the inline. For the user, the blinking cursor is visually inside the inline, not outside it. For the developer, the cursor (i.e. editor.selection) is inside the inline, not outside it. The definition of "the cursor" is "this is where your text will go when you type". To break that behavior is really jarring. * Slate's principle that "all of its logic is implemented with a series of plugins". If the current behavior is actually desirable in some circumstance, it should be in a plugin, not core. It's harder and less elegant for me to remove the core behavior with my own plugin. * Comparison with other editors. The following editors all insert text at the end of the inline, as expected: default contenteditable, Medium, Coda.io, Google Docs, OneNote, Evernote, QuillJS, TinyMCE, EditorJS, ProseMirror. Two editors with the current buggy behavior are Notion and Dropbox Paper, but I find it hard to imagine that their current behavior on this issue is actually designed, and not just accidental. * Usability: how else is the user supposed to enter text at the end of the inline ..? The only way seems to be to insert text before the end of the inline, and then delete the rest of the inline. This is obviously horrible. * add changeset * Fix test: insert at the end of an inline should _not_ have special behavior * The selection is no longer moved in insertText so we don't need this special case * fix:prettier * Revert "The selection is no longer moved in insertText so we don't need this special case" This reverts commit f9f36cd43937ed44272294c1c3c19ca2f3302f2d. * Explain the real reason for this special case - native browser bugs --- .changeset/dirty-mayflies-relate.md | 5 +++++ .../slate-react/src/components/editable.tsx | 5 +++-- packages/slate/src/create-editor.ts | 21 ------------------- .../insertText/selection/inline-end.tsx | 7 ++++--- 4 files changed, 12 insertions(+), 26 deletions(-) create mode 100644 .changeset/dirty-mayflies-relate.md diff --git a/.changeset/dirty-mayflies-relate.md b/.changeset/dirty-mayflies-relate.md new file mode 100644 index 000000000..990435560 --- /dev/null +++ b/.changeset/dirty-mayflies-relate.md @@ -0,0 +1,5 @@ +--- +'slate': patch +--- + +Allow typing at the end of inline elements diff --git a/packages/slate-react/src/components/editable.tsx b/packages/slate-react/src/components/editable.tsx index f0c45fe62..5575f7d08 100644 --- a/packages/slate-react/src/components/editable.tsx +++ b/packages/slate-react/src/components/editable.tsx @@ -288,7 +288,7 @@ export const Editable = (props: EditableProps) => { event.data && event.data.length === 1 && /[a-z ]/i.test(event.data) && - // Chrome seems to have issues correctly editing the start of nodes. + // Chrome has issues correctly editing the start of nodes: https://bugs.chromium.org/p/chromium/issues/detail?id=1249405 // When there is an inline element, e.g. a link, and you select // right after it (the start of the next node). selection.anchor.offset !== 0 @@ -301,7 +301,8 @@ export const Editable = (props: EditableProps) => { native = false } - // and because of the selection moving in `insertText` (create-editor.ts). + // Chrome also has issues correctly editing the end of nodes: https://bugs.chromium.org/p/chromium/issues/detail?id=1259100 + // Therefore we don't allow native events to insert text at the end of nodes. const { anchor } = selection const inline = Editor.above(editor, { at: anchor, diff --git a/packages/slate/src/create-editor.ts b/packages/slate/src/create-editor.ts index 7e4bd2122..82e07ce2d 100644 --- a/packages/slate/src/create-editor.ts +++ b/packages/slate/src/create-editor.ts @@ -162,27 +162,6 @@ export const createEditor = (): Editor => { const { selection, marks } = editor if (selection) { - // If the cursor is at the end of an inline, move it outside of - // the inline before inserting - if (Range.isCollapsed(selection)) { - const inline = Editor.above(editor, { - match: n => Editor.isInline(editor, n), - mode: 'highest', - }) - - if (inline) { - const [, inlinePath] = inline - - if (Editor.isEnd(editor, selection.anchor, inlinePath)) { - const point = Editor.after(editor, inlinePath)! - Transforms.setSelection(editor, { - anchor: point, - focus: point, - }) - } - } - } - if (marks) { const node = { text, ...marks } Transforms.insertNodes(editor, node) diff --git a/packages/slate/test/transforms/insertText/selection/inline-end.tsx b/packages/slate/test/transforms/insertText/selection/inline-end.tsx index ba5b89c95..de1c7b42a 100644 --- a/packages/slate/test/transforms/insertText/selection/inline-end.tsx +++ b/packages/slate/test/transforms/insertText/selection/inline-end.tsx @@ -20,9 +20,10 @@ export const output = ( one - two - four - + + twofour + + three