How to get the index of list item in ordered list

Hello,I’m new to ProseMirror,I need to custom li element’s number style, so maybe I need to get the index of list item,but I have no idea about how to implement

I have a solution after searching and testing for several hours, but I’m not sure if my code is good enough.For example, I don’t know why I need to +1 after pos+offset, I do it just because it can work in my tests.

export function customListPlugin() {
  return new Plugin({
    appendTransaction: (transactions, oldState, newState) => {
      if(!transactions.find(tr => tr.docChanged )) return;
      let trans = newState.tr
      newState.doc.descendants((node,pos) => {
        if(node.type.name != 'ordered_list') return false;
        node.forEach((child,offset,index) => {
          if(child.attrs.index != index + 1){
            trans.setNodeMarkup(pos+offset+1,undefined,{...child.attrs,index:index+1})
          }
        })
        return false
      })
      if(trans.docChanged) return trans
    }
  })
}
  1. I don’t know why I need to +1 after pos+offset, I do it just because it can work in my tests.

    • That is likely because you are targeting the list wrappers (pos), so the absolute position of the nested LI node would be (pos + 1 + offset) from there.
  2. Your solution looks fine with this approach, although its possible the best code would only run / iterate through entire document when applicable, as this approach above will catch any edit to the document - perhaps it can run only when inserting / removing / adjusting list items.

  3. At the end your descendants loop: return false

    • https://prosemirror.net/docs/ref/#model.Node.descendants

    • This will early return from diving into hierarchical nested lists just so you know. So if you allow for deeply nested lists, this solution will miss those (might be worth adding to your unit tests?)

  4. If you are going to always iterate through all document descendants and only need to render a different style on render, you might be better off using Node decorations, which dont require a transaction. The solution would look quite similar to what you have now and also wouldnt require any additional attributes to be stored on Nodes

    • This also opens up a solution that is more performant (decorations can be cached, but not necessary)

    • This approach could also allow for an insertable widget at the list item’s start location that can either have events or an even more customizable render setup.

Thanks for your reply! Your suggestions are very useful. At first I want to ban the nested lists, and use indent to make the list looks like nested, because I think the logic may be easier without nested case, but I don’t know how to handle when the text is copied from other doc or website which contains nested list.

I still think your current solution will be simpler, just less performant (it may or may not matter for you at this point)

But with regards to mutating in attributes on incoming pastes; This should help: ProseMirror Reference manual

If you go with the decoration approach, this wouldnt be needed.

As for simulating nested lists with indents - I am not convinced that is the right approach although this is how Google Docs implementation seems to work. There will be pros / cons here worth evaluating for future commands / implementation.

Thx again,I think I will try nested list first, I have trouble with list type toggle because I haven’t understood the api, but It not a very important feature I think, hope I can work it out. Thanks for your time.