Insert link + special styling behavior

I’m trying to customize link insertion and link style behavior.

I want to be able to insert new links without highlighting text (user provides link url and link text). Additionally I’d like the cursor positions within and at the edges of the link to be within the link style, BUT hitting space at the edge of the link should remove the style.

So if I have a link “foo link bar”, typing anywhere within or next to “link” should change the link text. If I click my cursor to the right of “k” and then hit space, I should be out of link style.

How can I achieve this?

Here’s what I have (modified from https://github.com/ProseMirror/prosemirror/issues/83). This works for inserting the link but hitting space at the edge does not exit the style.

    LinkStyle.attachCommand("insertLink", type => ({
      label: "Insert a link",
      run(pm, href, text, title) {
        // Could not get replaceSelection to take the style directly :(
        pm.setStyle(type, true, {href, title});
        pm.replaceSelection(pm.schema.text(text)).apply(andScroll);
        pm.setStyle(type, false);
      },
      params: [
        {name: "Target", type: "text"},
        {name: "Text", type: "text", default: ""},
        {name: "Title", type: "text", default: ""}
      ],
    }))

Thanks for any help on this!

Your code actually seems to work (though with the current master branch you have to say pm.tr.replaceSelection – sorry!). But note that the current style-at-cursor is remembered only if the cursor stays at that same place. The next time you update the selection (even by clicking on the editor), it’ll reset to the style in front of the cursor. Maybe that’s what’s happening your test case? (I.e. to test from the console, insert the link in a timeout, and make sure the editor is already focused when it is inserted.)

This unsets the style so that typing will not be within the linkStyle, however if you then move your cursor back to the end of the link, your next characters (including spaces) will be within a link.

Something like the following get’s the google docs behavior where typing within link changes link text, typing at edges (before and end) is without the link style.

export function spanStylesAt(doc, pos) {
  let parent = doc.path(pos.path)
  if (!parent.isTextblock) return empty

  let childBefore = parent.childBefore(pos.offset);
  let node = childBefore.node || parent.firstChild
  let styles = node ? node.styles : empty

  // Remove link from styles if we are at the end of the link node
  if (node && node.text.length == childBefore.innerOffset) {
    return styles.filter(function(style) {
      return style.type.name != "link";
    });
  } else {
    return styles
  }
}

Is there a better way to achieve this? Somehow getting LinkStyle it’s own span styles at? I think this google docs esque behavior will suffice and hopefully I won’t require any more custom style behavior. There’s def. a concern on performance if this is executing every key.