-
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
[Slate-React] Inline placeholder is treated as part of editor content #1344
Comments
@blakeembrey thanks for opening this. The issue is we're kind of constrained by what CSS/HTML allow us to do here. We render the placeholder as a sibling of the node's inner content itself (before the content to be exact). By default, the placeholder has An alternative would be to use I'm not sure there's a way to render |
Based on my limited knowledge of the project and some personal thoughts, here's an approach I would consider taking (not sure if it even matches up with the object model used by Slate.js - if not, I'm happy to create a separate project to demonstrate and flesh out the idea more thoroughly first). First, make the placeholder part of the model itself. This could have interesting side-effects later down the line for different use-cases, but if each object in the model manages selection events for itself the "placeholder" object could say "on selection move the selection to the beginning of the element". This would avoid the need entirely needing to have zero width and it'd just be regularly selectable - just the selection event would immediately change (like it is today anyway) to where it says it should go based on selection type. Once you have the "placeholder" node available, if there's a "render" change (e.g. normalize step that occurs after input) and it's part of the editor stack, the final listener can hook into it and automatically append the placeholder when no other nodes exist. On normalization after input, it can strip itself also from the total value. Honestly, not sure if anything I'm saying is making any sense and I haven't played enough with building something myself, so maybe I'll need to make that demo anyway 😄 |
@blakeembrey I'm not sure I want to make a placeholder node part of the model itself though. It seems like that means extra normalization logic, etc. for something that isn't really part of the "document" data at all (at least in the general case). For most people the placeholder is simply a styling concern that should be handled in the rendering layer, but not reflected in the data's "truth" itself (eg. it shouldn't be serialized ever, it shouldn't be "editable", it shouldn't affect selection behavior, etc.) At least that's how I currently think about it. That said... In this specific case, (ie. with this placeholder use case considered as an edge case that's not the general one), this is possible already by using an inline node with But that sounds like it's solving different, grander goals than the original issue above. There's the pure rendering issue where the placeholder is currently offsetting the content. Then there's the "interesting side-effects" which can be separated from this. They could be combined and solved via "placeholder as data", but I think that would make the 90% case more confusing. From what I can tell, adding the placeholder into the data model, and being forced to manage it on every change, seems like overkill for the 90% case. Instead, trying to find a pure HTML/CSS rendering solution to solve this behavior sounds better. This lines up with how the native DOM API's treat placeholders. |
Ok, so did a bunch of digging. The cursor jump is caused by https://stackoverflow.com/questions/27786048/why-is-my-contenteditable-cursor-jumping-to-the-end-in-chrome - when placed next to the One workaround would be to move the placeholder out of the Edit: I see the jumping is probably why you put the placeholder before the node children instead of after too. |
FWIW, if <div className={classnames(styles.container, className)}>
<Editor
state={this.state.state}
plugins={this.props.plugins}
ref={editor => (this.editor = editor)}
className={classnames(styles.editor, editorClassName)}
onBlur={onBlur}
onFocus={onFocus}
onChange={change => this.onChange(change)}
/>
{!value ? (
<div
className={classnames(styles.placeholder, placeholderClassName)}
onClick={() => this.editor.focus()}
>
{placeholder}
</div>
) : (
undefined
)}
</div> |
Update: I cannot reproduce it. It seems as long as you have a block in the beginning (even it is empty), the cursor will move to the right place... |
@zhujinxuan draft.js renders it outside of the actual content though. The problem here is that it is mixed with the contenteditable content, causing problems. Any updates on this problem? |
Oh actually, when adding |
When rendering an inline placeholder, it's treated as part of the document and the cursor always appears after the placeholder (which doesn't feel natural). My thought was maybe this has something to do with rendering and Slate.js measurements including the placeholder for cursor positioning.
The text was updated successfully, but these errors were encountered: