-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow typing at the end of an inline element #4578
Allow typing at the end of an inline element #4578
Conversation
This fixes ianstormtaylor#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.
🦋 Changeset detectedLatest commit: 3bbc418 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
The current behavior was added explicitly in #3260 to fix #3253, and there's still a test for it in https://github.com/ianstormtaylor/slate/blob/main/packages/slate/test/transforms/insertText/selection/inline-end.tsx There's also some code in I think the fix in #3260 was a mistake. The issue reported in #3253 is not correct; it is possible to navigate past the end of an inline. If it's the last element in the document, you can arrow down (or drag the cursor down) to move outside the inline; or if it's not the last element, you can move one position past the end of the inline, then back again. This works in all the browsers I tested (Chrome, Safari, Firefox, all on Mac). To see this, try moving the cursor in this Slate Explorer playground and see where the |
@jaked good catch. I've updated the test and removed that code in |
Here's what I've found so far. With this PR in its current state, typing at the end of an inline causes a crash. The new text is inserted both at the end of the inline (good), and immediately after the inline element as a new DOM text node in an invalid position (bad). Slate then can't find a Slate point for this invalid new DOM text node, and so crashes. The stuff in |
It certainly seems to be the native input event causing the problem. If I modify I'll try to isolate this buggy Chrome behavior. I'm guessing it's related to slate/packages/slate-react/src/components/editable.tsx Lines 284 to 286 in 43e740c
But in short, I now believe that the special-case in |
So here's the isolated Chrome bug: https://codepen.io/jameshfisher/pen/gOxbBzy I'll submit this as a Chromium bug. |
Submitted Chromium issue: https://bugs.chromium.org/p/chromium/issues/detail?id=1259100 |
…ed this special case" This reverts commit f9f36cd.
@jaked so at the end of all that, I've left in the special-case code, and instead changed its comment - the real reason it exists is that native Chrome has (rather unbelievably) the very same bug we're trying to remove from Slate: it doesn't allow typing at the end of an (Honestly, the #3888 change really scares me, considering how buggy and inconsistent the native contenteditable implementations are.) |
The integration tests keep failing, but it looks like a flaky test to me. |
Yes, I wouldn't worry about that too much.
Me as well. I've been debating whether we should revert it or try to work through the various issues it has introduced. |
Okay, great. I think this PR is ready for review then.
I really, really, really appreciate the simplicity of "just re-render every time". If the goal is to make spellcheck less flickery, it feels like there must be a less radical solution (e.g. opening bug reports with buggy browser vendors, or somehow disabling spellcheck for ~1 second after each editor change). It also looks the native events doesn't help the "support IME" goal, since it currently only works on characters |
@jameshfisher could you please look at main after the landing of #4605 and then make sure this works fine on top of that. I'm going to release 0.67.0 now, but happy to do a 0.67.1 once this change has been verified on top of that. Thanks! |
Yep, will look at it today
…On Mon, Oct 18, 2021, 21:08 Dylan Schiemann ***@***.***> wrote:
@jameshfisher <https://github.com/jameshfisher> could you please look at
main after the landing of #4605
<#4605> and then make sure
this works fine on top of that. I'm going to release 0.67.0 now, but happy
to do a 0.67.1 once this change has been verified on top of that. Thanks!
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#4578 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AABIYNX47EIOVBP7DJ63MXTUHR5DZANCNFSM5FTMSQ2Q>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub>.
|
@dylans this looks good to me. Tests still pass. Examples behave as I expect. (This is clearest if you edit the "links" example to add padding and background color to the inline link. The examples suffer from a lack of non-trivial inline elements. I'm going to contribute a new example in a separate PR.) I don't entirely understand #4605 but it looks good - perhaps less scary than previous implementation. |
@jameshfisher I've landed this, but it's definitely introducing a regression. If you add a link to the end of a line, you cannot leave the link with the arrow keys (right arrow key goes to next line instead of outside the link. Going to the next line and then going back with the left arrow key does allow you to move the cursor outside the link. |
@dylans this seems like expected/desired behavior given how the browser selection works, but it is sometimes annoying. I checked Notion and Google Docs and they both have the original behavior for links (edge of a link is always outside), which is also sometimes annoying! I think @jameshfisher 's change makes sense for inlines in general, and it matches the behavior of marks. Links might be kind of a special case? Maybe applications need to be careful to leave the selection outside the link after creating / pasting a link so you don't accidentally edit the link text. |
This was perfect timing since I'm currently working on fixing this problem for inline nodes in our text editor. Unfortunately, the new behavior is also undesirable since it forces you to hit enter and backtrack like @jaked mentioned. In my opinion, this is really no better than forcing a user to backtrack in the middle of an inline node to add the text they wanted and then delete the irrelevant bits. Would it be possible to introduce a new placeholder node type in addition to the empty text node ( const tree = {
type: 'paragraph',
children: [
{ text: '...' },
{
type: 'hyperlink',
href: 'google.com',
children: [...]
},
{ text: 'some unique placeholder' },
{ text: '' }
]
} That way, pressing the right arrow key somehow positions the selection after that placeholder node. Maybe Slate could detect the right arrow key at the end of an inline and insert a space after it, but not part of the inline? Just throwing some ideas out there. |
It is something I do pretty regularly in our codebase and also in Plate (though this example inserts an extra empty text node) e.g. https://github.com/udecode/plate/blob/a504a1a91a6195a6e8d8c4d7ce5ec0844e9be733/packages/elements/mention/src/getMentionOnSelectItem.ts . Historically this is something slate has not tried to do, but I think it's worth trying to solve. |
Slate default behavior for arrow left/right is here. It uses In my application I've effectively customized the arrow left/right behavior to use But, as the Slate docs note, We can try to improve the default behavior, but I'm sure we can't please everyone. Since Slate is schema-agnostic, and doesn't have access to CSS, Slate can't reliably know when and whether the "might be thought of as the same position" rule applies. I think this has to be decided by the application developer, for their schema and their CSS. So instead I think we should make it easy+simple to customize this behavior. We should have an official example that shows some different inline elements, and how to modify the navigation behavior appropriately for each of them. (Note that I also had to fight with some browser bugs when implementing this |
@jameshfisher I agree but also disagree. I think it's definitely worth improving the default behavior for inlines at the library level. Devs shouldn't have to customize functionality like how typing behaves in inline nodes—there should be a sensible default that everyone can use out of the box. With this change, there's no good way to break out of inline nodes once you create them, unless you press enter and backtrack. So it may actually create a more frustrating user experience unless it's customized. I'm eagerly awaiting this feature for our app. Are there any plans to improve the typing experience before it gets released? |
I've opened a PR #4615 which contributes an official example of a custom inline that should clearly work with "offset" behavior: an "editable button". It shows the several hoops that I've had to jump through to get something like this working. I think we can use this official example as a medium for discussing Slate's default behavior, and how developers can customize it. |
* Allow typing at the end of an inline This fixes ianstormtaylor#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 f9f36cd. * Explain the real reason for this special case - native browser bugs
Description
Steps to reproduce the buggy behavior:
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 and was added in #3260. I nevertheless claim that this is a bug, or at least a misfeature in core. My expected behavior comes from:
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.Issue
Fixes: #4524
Example
slate-inline-bug.mp4
Checks
yarn test
.yarn lint
. (Fix errors withyarn fix
.)yarn start
.)yarn changeset add
.)