How to have a mark with content hide/show dynamically

I have some mark with userId attrs, and I have a select to determine which mark should show.

Now I use markview

  • Builds span elements with data-uid
  • Applies display/visibility based on selectedUid

It works for most situation. But it has a problem when all the content is hidden in a paragraph like <p><span data-uid=”test” class=”hidden”>…</span><p>, one can not input any text in the paragraph.

I wonder what is the best solution for my case.

Mark (or node) DOM representations cannot depend on data outside of the mark or node. To do this, you’ll have to use decorations, and a plugin that updates them as appropriate when your toggle (whose value you could store in the plugin state) changes value.

Thank you Margin.

But does the decorations method solve the editting problem when all the content is hidden in a paragraph like <p><span data-uid=”test” class=”hidden”>…</span><p>(suppose the hidden class is added by decorations) ? AFAIK, there would be no ProseMirror-trailingBreak in the paragraph, and I can not input any text, right?.

If the content at the end of a textblock is uneditable (contenteditable=false), the library will also add the <br> kludge node. So maybe making the decoration both uneditable and display: none helps.

I tried

function buildDecorations(doc) {
  const decorations = []
  doc.descendants((node, pos) => {
    if (!node.isText) {
      return true
    }
    for (const mark of node.marks) {
      if (mark.type.name === 'mymark') {
        const uid = mark.attrs.uid
        const shouldShow = selectedUid === 'all' || (uid && selectedUid === uid)
        if (!shouldShow) {
          const deco = Decoration.inline(pos, pos + node.nodeSize, {
            class: 'hidden',
            'contenteditable': 'false',
          })
          decorations.push(deco)
        }
      }
    }
    return true
  })
  return decorations
}

with this function, but it results in something like:

<p><span data-uid=”test”>
    <span contenteditable="false" class="hidden">...</span>
</span></p>

It adds another `span` element inside, and then the <br> kludge node will not be added.

Ah, you are right, the code that adds the <br> won’t add it after uneditable text nodes. Unfortunately, even if I adjust that, the <br> still doesn’t help, since the editor will still place the cursor in the hidden element (which it believes to be part of its content, and on the cursor position, and thus the appropriate place for the selection), which breaks text input.

It sounds like ProseMirror just doesn’t really support what you are trying to do here.

Sad to hear that.

Is there any workaround? Replace the mark with inline node? or even atom?

If these are leaf nodes (or atoms) the editor won’t try to put the cursor inside them, so that might help with the cursor problem.