Tiptap: toggleBlockType won't keep existing attrs

Created on 5 Feb 2019  路  4Comments  路  Source: ueberdosis/tiptap

Wondering if anyone can help here please...

I've written an extension that handles text-align and line-height. It'll manage to set the alignment or line height correctly, but only one of the other.

If I set line-height, it reverts the alignment back to whatever is set as default (left).

Any ideas? Code below. No doubt i'm missing something obvious.

import { Node } from "tiptap";
import { toggleBlockType } from "tiptap-commands";

export default class ParagraphStyle extends Node {
  get name() {
    return "paragraphStyle";
  }

  get schema() {
    return {
      attrs: {
        lineSpacing: {
          default: null,
        },
        align: {
          default: "left",
        },
      },
      content: "inline*",
      group: "block",
      parseDOM: [
        {
          tag: "p",
          getAttrs(dom) {
            const { lineHeight, textAlign } = dom.style;

            let align = textAlign || "";

            const lineSpacing = lineHeight ? lineHeight : null;

            const id = dom.getAttribute("id") || "";

            return { align, lineSpacing, id };
          },
        },
      ],
      toDOM(node) {
        const { align, lineSpacing, id } = node.attrs;
        const attrs = {};
        let style = "";

        if (align && align !== "left") {
          style += `text-align: ${align};`;
        }

        if (lineSpacing) {
          style += `line-height: ${lineSpacing};`;
        }

        if (style) {
          attrs.style = style;
        }

        if (id) {
          attrs.id = id;
        }

        return ["p", attrs, 0];
      },
    };
  }

  commands({ type, schema }) {
    return attrs => toggleBlockType(type, schema.nodes.paragraphStyle, attrs);;
  }
}

And being set with:

commands.paragraphStyle({lineSpacing: $event.target.value})

or

@click="commands.paragraphStyle({align: 'left'})"
question

Most helpful comment

Absolutely! I've read that thread a few times, and came back to it a lot during my struggles!

I've got a bit more to figure out on it, but will absolutely share what I find when I have something more concrete.

All 4 comments

Ok, I sort of have a working fix for this.

A bit messy, so I'll definitely be cleaning this up.

Essentially, look into the EditorState, get the cursor/selection position, get the parent node, get it's attrs and then use that as a base to assign. I'm using lodash's clone which I don't like, but for now it works for my requirements.

commands({ type, schema }) {
    return attrs => (state, dispatch, view) => {
      const { selection } = state;
      const position = selection.$cursor
        ? selection.$cursor.pos
        : selection.$to.pos;
      let $pos = state.doc.resolve(position);
      let $parent = $pos.parent;
      let updateAttrs = $parent ? clone($parent.attrs) : {};

      Object.assign(updateAttrs, attrs);

      const isActive = nodeIsActive(state, type, attrs);

      if (isActive) {
        return setBlockType(toggletype)(state, dispatch, view);
      }

      return setBlockType(type, updateAttrs)(state, dispatch, view);
    };
  }

Hacked from TipTaps toggleBlockType command, and some bits from ProseMirror's setBlockType command.

Next to figure out getting the status of all of these for the button active states!

@paulrose Neato! Regarding the alignment stuff, I have an open discussion about how to handle that for multiple node types (#180.) It sounds like you are taking a similar approach to the one discussed there. Would you be willing to contribute your 2cents to that thread? Ideally it would be great to have a way to package up alignment (or text color, line height, etc. as you have done here) as extensions of some kind (or at least examples in the docs) to share with others.

Absolutely! I've read that thread a few times, and came back to it a lot during my struggles!

I've got a bit more to figure out on it, but will absolutely share what I find when I have something more concrete.

here is my solution
font.js defined in marks

import { Mark } from 'tiptap'
import { updateMark, markInputRule, markPasteRule } from 'tiptap-commands'

export default class Font extends Mark {
  get name () {
    return 'font'
  }

  get schema () {
    return {
      attrs: {
        color: {
          default: ''
        },
        fontSize: {
          default: ''
        },
        fontFamily: {
          default: ''
        },
        backgroundColor: {
          default: ''
        },
        lineHeight: {
          default: ''
        }
      },
      parseDOM: [
        {
          tag: 'span',
          getAttrs: dom => {
            return {
              color: dom.style.color,
              fontSize: dom.style.fontSize,
              fontFamily: dom.style.fontFamily,
              backgroundColor: dom.style.backgroundColor,
              lineHeight: dom.style.lineHeight,
            }
          }
        }
      ],
      toDOM: (node) => {
        console.log(node)
        return ['span', {
          style: `color:${node.attrs.color};font-size:${node.attrs.fontSize};font-family:${node.attrs.fontFamily};background-color:${node.attrs.backgroundColor};line-height:${node.attrs.lineHeight};`
        }, 0]
      }
    }
  }

  keys ({ type }) {
    return {
      'Mod-f': updateMark(type)
    }
  }

  commands ({ type }) {
    return attrs => updateMark(type, attrs)
  }

  inputRules ({ type }) {
    return [
      markInputRule(/(?:\*\*|__)([^*_]+)(?:\*\*|__)$/, type)
    ]
  }

  pasteRules ({ type }) {
    return [
      markPasteRule(/(?:\*\*|__)([^*_]+)(?:\*\*|__)/g, type)
    ]
  }
}

define a function to update line-height, actually i don't write like this,just as a reference

function handleLineHeight(lineHeight, command = commands.font, attrs = getMarkAttrs('font')){
      attrs.lineHeight = lineHeight
      console.log(attrs)
      command({
        ...attrs
      })
 }
Was this page helpful?
0 / 5 - 0 ratings

Related issues

afwn90cj93201nixr2e1re picture afwn90cj93201nixr2e1re  路  3Comments

asseti6 picture asseti6  路  3Comments

jetacpp picture jetacpp  路  3Comments

ageeye-cn picture ageeye-cn  路  3Comments

dolbex picture dolbex  路  3Comments