Applying custom fonts/color

Hello everyone… I’m starting with prosemirror and would need some advices concerning best practices for a specific usecase. so my requirement is i want to set a color picker and font-size dropdown in the editor. will i able to achieve this with PM??, user can select color or font-size then it should be applied to the selection part of the editor. Till now i was going with the marks to implement these feature,

  • I’ve created a mark schema with the default attributes as null.
  • On clicking the color/font-size value then it will add mark to the selection with the appropriate styles. below is my schema for color
get schema() {  
    return {
      attrs: {
        color: {
          default: null
        }
      },
       group: "block",
      content: "inline*",
      parseDOM: [
        {
          tag: "span",
          getAttrs: node => ({ color: node.getAttribute('color') })
        }
      ],
      toDOM: (node) => {
        return [`span`, 
       {
          class: `custom-color ${node.attrs.color}`,
          style: `color:${node.attrs.color}`
        },
          0
        ]
        
      },
    };
  }

It will be all good till the document is saved (all works fine both font-size and color). when the document is saved and then if we go back or refresh the page the styles are getting default value i:e null. I know i have to store the values somewhere. how i can achieve this?? is going with the marks is fine or should i go with the node(ProseMirror Reference manual).

any helpful advise will be life saviour :slightly_smiling_face: thanks in advance!!

When the document doesn’t round-trip properly through HTML, that usually suggests a mismatch between your toDOM and parseDOM specs. In this case, it looks like the color is written to the DOM in the class and style attributes, but parseDOM tries to read it from the color attribute.

thanks for the reply!! :raised_hands:

yes… it was a mistake now i’ve modified my schema, toDOM takes color attributes. but still it giving me the same output. color attribute is also getting me null after refresh.

Is that is value is not getting parse or something??

Is there anything keypoint i’m missing?? here

Provide a demo will be helpful for location the issue. https://codesandbox.io/ :grinning:

I’m running out of time it could not be possible now.

here my schema

get schema() {  
    return {
      attrs: {
        color: {
          default: null
        }
      },
      group: "block",
      content: "inline*",
      parseDOM: [
        {
          tag: "span",
          getAttrs: node => ({ style: node.getAttribute('color') })
        }
      ],
      toDOM: (node) => {        
        return ["span", {
          class: `custom-color`,
          style: `color:${node.attrs.color}`,
          color: `${node.attrs.color}`
        },
          0
        ]
        
      },
    };
  }

This is my addMark func.

export default  function setMark(markType: any, attrs: object) {  
  return function (state: EditorState, dispatch: (tr: Transaction) => void) {      
      if (dispatch) {     
          let from = state.selection.from
          let to = state.selection.to
          if (from === to) {
              const position = state.tr.doc.resolve(from)
              const parentInfo = position.parent.childBefore(position.parentOffset)
              from = parentInfo.offset + 1
              to = from + (parentInfo.node?.nodeSize || 0) + 1
        }        
        
        dispatch(state.tr.addMark(from, to, markType.create(attrs)))

      }
      return true
    }
  }

It’s probably because in your parseDom you’re trying to read the color from the node (i.e. the span in this case) instead of from the style of the span/node. You might also look at the basic schema mark set up for another way to do it - e.g. how the font-weight is handled.

Actually I see you do try to set a color attribute on the span so maybe it’s that you will set a style on the span to just the color instead of a string like “color:” + node.getAttribute(‘color’) but you could debug the getAttrs method and just see what is happening.

1 Like

Yes @andrews, it appears he is missing the correct logic here, but since he has a color attribute on the Node, parseDom should contain:

color: node.getAttribute('color') rather than trying to add a style string in getAttrs (which will be ignored since there is no style attribute defined in schema; @marijn, I forget if Prosemirror either silently ignores or prints something to console )

Also, @junaid, if you are taking the route of having a color attr, you may not need the color attribute in toDom, since you could read the style map, parseDom: (node) => {color: node.style.color} but I don’t think it matters much. It ends up being redundant if you render it in two places (unless you use the attribute elsewhere)

I’m running out of time it could not be possible now.

Finally, @junaid, my suggestion is to more carefully read the documentation, as this is one of the easier Prosemirror architectural problems. If you are aiming to have more control over your implementation, you are going to need to understand the basics really well (as always.) That being said, always feel free to bring any issues / confusion here, I just think that if you have timelines / deadlines, this will pay off, as we can’t always answer immediately.

thanks a lot :raised_hands:

right :+1:

i’m sure that i’m missing something very common there!!