springload / draftail

📝🍸 A configurable rich text editor built with Draft.js
https://www.draftail.org/
MIT License
616 stars 64 forks source link

Inline entity editing controls present a confusing UI on empty selections #85

Closed thibaudcolas closed 7 years ago

thibaudcolas commented 7 years ago

Inline entities (created with Draft.js' RichUtils.toggleLink, eg. links, documents, etc) need text to be applied upon, via a selection. If there is no selection (the selection is "collapsed" in Draft.js terms), the editor still offers the entity creation UI but it will not produce any output nor display any warning.

Mandatory GIF, from https://www.draftail.org/, with the example Link implementation:

draftail-inline-entities-empty-selection

Ideally there would be a systematic solution for this – either prevent the editing UI from opening if the selection is collapsed, or add the "URLified" property of the entity as text (eg. adding a link to example.com on an empty selection will add example.com as the link text). I don't think this is possible without an API change - at the moment there is no distinction between inline and block entities, both implemented through entityTypes and sources (lower level abstractions allowing arbitrary behaviors, should probably be a separate API for both types), and there is no special treatment for the "URLified" property to use as text (there probably should be).

Until then, a simpler solution would be to change the entities' "source" in userland to prevent any UI from appearing if the selection is collapsed. For the Draftail example LinkSource, this would look something like:


class LinkSource extends React.Component {
    componentDidMount() {
        const { editorState, entity, options, onUpdate } = this.props;
+        
+        if (!editorState.getSelection().isCollpased()) {
            const url = global.prompt('Link URL', entity ? entity.getData().url : '');

            if (url) {
                const contentState = editorState.getCurrentContent();
                const contentStateWithEntity = contentState.createEntity(options.type, 'MUTABLE', {
                    url: url,
                });
                const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
                const nextState = RichUtils.toggleLink(editorState, editorState.getSelection(), entityKey);

                onUpdate(nextState);
            } else {
                onUpdate(editorState);
            }
+        }
    }

    render() {
        return null;
    }
}
thibaudcolas commented 7 years ago

@vincentaudebert assigning you for the "Until then" section. This needs to be done on the examples in: