Color Node Type

Category: Formatting • Detailed implementation guide with view integration notes

Schema Definition

Schema definition for the Color mark type:

{
  color: {
    attrs: {
      color: { default: '#000000' }
    },
  }
}

Model Representation

Example model representation:

{
  type: 'text',
  text: 'Colored text',
  marks: [{
    type: 'color',
    attrs: { color: '#ff0000' }
  }]
}

HTML Serialization

Converting model to HTML:

function serializeColorMark(text, mark) {
  const color = mark.attrs?.color || '#000000';
  return '<span style="color: ' + escapeHtml(color) + '">' + text + '</span>';
}

HTML Deserialization

Parsing HTML to model:

function extractColorMark(element) {
  if (element.tagName === 'SPAN' && element.style.color) {
    return {
      type: 'color',
      attrs: { color: element.style.color }
    };
  }
  return null;
}

function extractColorFromStyle(colorString) {
  // Convert rgb/rgba to hex if needed
  return colorString;
}

View Integration

View Integration Notes: Pay special attention to contenteditable behavior, selection handling, and event management when implementing this node type in your view layer.

View integration code:

// Applying color
function applyColor(color) {
  addMark({
    type: 'color',
    attrs: { color }
  });
}

// Color picker integration
function showColorPicker() {
  const picker = createColorPicker();
  picker.onChange = (color) => {
    applyColor(color);
  };
}

Common Issues

Common Pitfalls: These are issues frequently encountered when implementing this node type. Review carefully before implementation.

Common issues and solutions:

// Issue: Color format normalization
// Solution: Normalize to hex format
function normalizeColor(color) {
  if (color.startsWith('rgb')) {
    return rgbToHex(color);
  }
  return color;
}

// Issue: Color with other marks
// Solution: Color can coexist with other marks
function applyColorWithMarks(text, color, otherMarks) {
  let html = text;
  html = '<span style="color: ' + color + '">' + html + '</span>';
  otherMarks.forEach(mark => {
    html = wrapWithMark(html, mark);
  });
  return html;
}

Implementation

Complete implementation example:

class ColorMark {
  constructor(attrs) {
    this.type = 'color';
    this.attrs = { color: attrs?.color || '#000000' };
  }
  
  toDOM() {
    return ['span', { style: 'color: ' + this.attrs.color }, 0];
  }
  
  static fromDOM(element) {
    if (element.tagName === 'SPAN' && element.style.color) {
      return new ColorMark({ color: element.style.color });
    }
    return null;
  }
}