Apply font styles to Selection

Hi, is there a way to apply font size and other font styles to the Selection only? We used to use transaction.setNodeMarkup, but it applies styles on the whole node and I need on the selection only.

For example, I have a paragraph like: “Here is some text”. Then, I highlight a word text and want to make it 18px (other words are 16px), but font size changes on the whole paragraph, and not only on this word.

Thanks

How font size is modeled depends on your schema—if it’s an attribute on nodes, then it can only be set per-node. If it’s a mark (which seems unlikely if you’re using setNodeMarkup right now), it can be added to specific ranges with addMark.

thanks for the answer ) what I trying to do is to modify somehow setNodeMarkup function. Here is what I got. But now I get the error: “Invalid content type for paragraph”. ReplaceAroundStep is set on the node only too?

const node = editorView.state.doc.nodeAt(pos);
  const { tr } = editorView.state;
  if (!node) throw new RangeError("No node at given position");

  const newNode = type.create(attrs, null, marks || node.marks);
  if (node.isLeaf) return tr.replaceWith(pos, pos + node.nodeSize, newNode);

  const slice = new Slice(Fragment.from(newNode), 0, 0);

  return tr.step(new ReplaceAroundStep(from, to, from - 1, to, slice, 1, true));

Without knowing what your schema looks like, and what kind of structure change you’re trying to create, I can’t really say what’s going on here.

Here is my schema for paragraph node:

export const paragraph = {
  group: "block",
  attrs: {
    fontFamily: {
      default: "fontArchivo",
    },
    fontSize: {
      default: null,
    },
    textAlign: {
      default: "left",
    },
  },
  content: "inline*",
  toDOM(node) {
    return [
      "p",
      {
        class: node.attrs.fontFamily,
        style: `${
          node.attrs?.fontSize && `font-size: ${node.attrs?.fontSize}px`
        }; ${node.attrs?.textAlign && `text-align: ${node.attrs?.textAlign}`};`,
      },
      0,
    ];
  },
  parseDOM: [
    {
      tag: "p",
    },
  ],
};

I want to change fontSize and fontFamily attrs not for the whole paragraph but only for the selected piece of paragraph. setNodeMarkup applies the changes to the whole paragraph, therefore, I’m trying to modify this function.

Look into using marks, rather than node attributes, to represent font size and family.

Thanks! I implemented font size and font family as marks. But now have the problem that on start marks is not detected. What I mean: for example, I have this paragraph node where every word has different font size:

fontSize14 fontSize16 fontSize18

If I select the first letter (in this example f), the mark will be not detected here. It happens because before f - not mark, and after f - mar exists. But if I select the last letter, then everything fine, the mark is detected before this letter and after it. The question is how can I detect the mark before the first letter? I added the inclusive option to marks, so it detects the mark after the last letter. Below, is my mark:

export const fontSize = {
  attrs: {
    fontSize: {
      default: null,
    },
  },
  inclusive: true,
  parseDOM: [
    {
      tag: "span",
      getAttrs: node => ({ fontSize: node.getAttribute("fontSize") }),
    },
  ],

  toDOM(node) {
    return [
      "span",
      {
        style: `${
          node.attrs?.fontSize && `font-size: ${getFontSize(node)}px`
        };`,
      },
      0,
    ];
  },
};

Also, it affects the case when I want to start a new line and I cannot select a different font size before typing something. It doesn’t happened with the strong mark, for example

Here is a gif to show what I mean. The cursor is set as for default value but after I starting typing it gets bigger.

Is there a way to avoid this cursor jumping?

Right, with marks, the font size won’t be rendered unless there is any actual text that it’s applied to visible. That’s not something the library will solve for you.