CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-draft-js

A React framework for building text editors with immutable data models.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

conversion-utilities.mddocs/

Conversion Utilities

Functions for converting between Draft.js content and other formats including raw objects for serialization and HTML for import/export.

Capabilities

Raw State Conversion

Functions for converting between Draft.js ContentState and plain JavaScript objects suitable for JSON serialization.

convertToRaw (exported as convertToRaw)

Converts a ContentState to a raw JavaScript object that can be serialized to JSON.

/**
 * Convert ContentState to raw object for serialization
 * @param contentState - ContentState to convert
 * @returns Raw state object suitable for JSON serialization
 */
function convertToRaw(contentState: ContentState): RawDraftContentState;

convertFromRaw (exported as convertFromRaw)

Converts a raw JavaScript object back to a ContentState.

/**
 * Convert raw object to ContentState
 * @param rawState - Raw state object from JSON deserialization
 * @returns ContentState instance
 */
function convertFromRaw(rawState: RawDraftContentState): ContentState;

Usage Examples:

import { convertToRaw, convertFromRaw, EditorState } from "draft-js";

// Save editor content to storage
function saveContent(editorState) {
  const contentState = editorState.getCurrentContent();
  const rawContentState = convertToRaw(contentState);
  
  // Save to localStorage
  localStorage.setItem('draft-content', JSON.stringify(rawContentState));
  
  // Or send to server
  fetch('/api/save-content', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ content: rawContentState })
  });
}

// Load editor content from storage  
function loadContent() {
  const rawContentState = JSON.parse(
    localStorage.getItem('draft-content') || '{"blocks":[],"entityMap":{}}'
  );
  
  const contentState = convertFromRaw(rawContentState);
  return EditorState.createWithContent(contentState);
}

// Working with raw content
function analyzeRawContent(rawContentState) {
  console.log('Number of blocks:', rawContentState.blocks.length);
  console.log('Number of entities:', Object.keys(rawContentState.entityMap).length);
  
  rawContentState.blocks.forEach((block, index) => {
    console.log(`Block ${index}: ${block.type} - "${block.text}"`);
  });
}

// Modify raw content
function addPrefixToRawContent(rawContentState, prefix) {
  return {
    ...rawContentState,
    blocks: rawContentState.blocks.map((block, index) => {
      if (index === 0) {
        return {
          ...block,
          text: prefix + block.text
        };
      }
      return block;
    })
  };
}

HTML Conversion

Function for converting HTML strings to Draft.js content blocks.

convertFromHTML (exported as convertFromHTML)

Converts HTML string to Draft.js content blocks and entities.

/**
 * Convert HTML string to Draft.js content blocks
 * @param html - HTML string to convert
 * @param getSafeBodyFromHTML - Optional function to sanitize HTML
 * @param blockRenderMap - Optional block render map for custom elements
 * @returns Object containing content blocks and entity map
 */
function convertFromHTML(
  html: string,
  getSafeBodyFromHTML?: (html: string) => HTMLElement,
  blockRenderMap?: DraftBlockRenderMap
): {
  contentBlocks: Array<ContentBlock>,
  entityMap: any
};

Usage Examples:

import { convertFromHTML, ContentState, EditorState } from "draft-js";

// Convert HTML to editor state
function htmlToEditorState(html) {
  const { contentBlocks, entityMap } = convertFromHTML(html);
  
  if (contentBlocks) {
    const contentState = ContentState.createFromBlockArray(
      contentBlocks,
      entityMap
    );
    return EditorState.createWithContent(contentState);
  }
  
  return EditorState.createEmpty();
}

// Import HTML content
function importHtmlContent(htmlString) {
  // Basic HTML import
  const editorState = htmlToEditorState(htmlString);
  
  return editorState;
}

// Import with custom sanitization
function importSanitizedHtml(htmlString) {
  const getSafeBodyFromHTML = (html) => {
    // Create temporary DOM element
    const doc = new DOMParser().parseFromString(html, 'text/html');
    
    // Remove dangerous elements
    const scripts = doc.querySelectorAll('script');
    scripts.forEach(script => script.remove());
    
    return doc.body;
  };
  
  const { contentBlocks, entityMap } = convertFromHTML(
    htmlString,
    getSafeBodyFromHTML
  );
  
  if (contentBlocks) {
    const contentState = ContentState.createFromBlockArray(
      contentBlocks,
      entityMap
    );
    return EditorState.createWithContent(contentState);
  }
  
  return EditorState.createEmpty();
}

// Handle paste from HTML
function handlePastedText(text, html, editorState) {
  if (html) {
    const { contentBlocks, entityMap } = convertFromHTML(html);
    
    if (contentBlocks) {
      const contentState = editorState.getCurrentContent();
      const selection = editorState.getSelection();
      
      // Create fragment from pasted content
      const pastedContentState = ContentState.createFromBlockArray(
        contentBlocks,
        entityMap
      );
      const fragment = pastedContentState.getBlockMap();
      
      // Insert fragment
      const newContentState = Modifier.replaceWithFragment(
        contentState,
        selection,
        fragment
      );
      
      const newEditorState = EditorState.push(
        editorState,
        newContentState,
        'insert-fragment'
      );
      
      return newEditorState;
    }
  }
  
  return null; // Fall back to default handling
}

Content Export Utilities

Utility functions for exporting Draft.js content to various formats.

/**
 * Export utilities for converting Draft.js content to other formats
 */

// Export to plain text
function exportToPlainText(contentState: ContentState, delimiter?: string): string {
  return contentState.getPlainText(delimiter || '\n');
}

// Export to HTML (basic implementation)
function exportToHTML(contentState: ContentState): string {
  const blocks = contentState.getBlocksAsArray();
  
  return blocks.map(block => {
    const text = block.getText();
    const type = block.getType();
    
    switch (type) {
      case 'header-one':
        return `<h1>${text}</h1>`;
      case 'header-two':
        return `<h2>${text}</h2>`;
      case 'header-three':
        return `<h3>${text}</h3>`;
      case 'blockquote':
        return `<blockquote>${text}</blockquote>`;
      case 'code-block':
        return `<pre><code>${text}</code></pre>`;
      case 'unordered-list-item':
        return `<li>${text}</li>`;
      case 'ordered-list-item':
        return `<li>${text}</li>`;
      default:
        return `<p>${text}</p>`;
    }
  }).join('\n');
}

// Export with inline styles and entities
function exportToRichHTML(contentState: ContentState): string {
  const blocks = contentState.getBlocksAsArray();
  
  return blocks.map(block => {
    let html = '';
    const text = block.getText();
    const type = block.getType();
    const characterList = block.getCharacterList();
    
    // Process character by character for inline styles
    for (let i = 0; i < text.length; i++) {
      const char = text[i];
      const metadata = characterList.get(i);
      const styles = metadata.getStyle();
      const entityKey = metadata.getEntity();
      
      let styledChar = char;
      
      // Apply inline styles
      if (styles.has('BOLD')) {
        styledChar = `<strong>${styledChar}</strong>`;
      }
      if (styles.has('ITALIC')) {
        styledChar = `<em>${styledChar}</em>`;
      }
      if (styles.has('UNDERLINE')) {
        styledChar = `<u>${styledChar}</u>`;
      }
      
      // Apply entities
      if (entityKey) {
        const entity = contentState.getEntity(entityKey);
        if (entity.getType() === 'LINK') {
          const { url } = entity.getData();
          styledChar = `<a href="${url}">${styledChar}</a>`;
        }
      }
      
      html += styledChar;
    }
    
    // Wrap in block element
    switch (type) {
      case 'header-one':
        return `<h1>${html}</h1>`;
      case 'header-two':
        return `<h2>${html}</h2>`;
      case 'header-three':
        return `<h3>${html}</h3>`;
      case 'blockquote':
        return `<blockquote>${html}</blockquote>`;
      case 'code-block':
        return `<pre><code>${html}</code></pre>`;
      default:
        return `<p>${html}</p>`;
    }
  }).join('\n');
}

Complete Export Example:

import { convertToRaw, EditorState } from "draft-js";

// Multi-format export utility
class ContentExporter {
  static exportAs(editorState, format) {
    const contentState = editorState.getCurrentContent();
    
    switch (format) {
      case 'raw':
        return convertToRaw(contentState);
        
      case 'json':
        return JSON.stringify(convertToRaw(contentState), null, 2);
        
      case 'plain':
        return contentState.getPlainText('\n');
        
      case 'html':
        return this.exportToHTML(contentState);
        
      case 'markdown':
        return this.exportToMarkdown(contentState);
        
      default:
        throw new Error(`Unsupported export format: ${format}`);
    }
  }
  
  static exportToHTML(contentState) {
    // Implementation for HTML export with styles and entities
    return exportToRichHTML(contentState);
  }
  
  static exportToMarkdown(contentState) {
    const blocks = contentState.getBlocksAsArray();
    
    return blocks.map(block => {
      const text = block.getText();
      const type = block.getType();
      
      switch (type) {
        case 'header-one':
          return `# ${text}`;
        case 'header-two':
          return `## ${text}`;
        case 'header-three':
          return `### ${text}`;
        case 'blockquote':
          return `> ${text}`;
        case 'code-block':
          return `\`\`\`\n${text}\n\`\`\``;
        case 'unordered-list-item':
          return `- ${text}`;
        case 'ordered-list-item':
          return `1. ${text}`;
        default:
          return text;
      }
    }).join('\n\n');
  }
}

// Usage
function exportContent(editorState, format) {
  try {
    const exported = ContentExporter.exportAs(editorState, format);
    console.log(`Exported as ${format}:`, exported);
    return exported;
  } catch (error) {
    console.error('Export failed:', error);
    return null;
  }
}

Types

Conversion-Related Types

// Raw content state structure
interface RawDraftContentState {
  blocks: Array<RawDraftContentBlock>;
  entityMap: {[key: string]: RawDraftEntity};
}

// Raw content block
interface RawDraftContentBlock {
  key: string;
  type: DraftBlockType;
  text: string;
  characterList: Array<RawDraftCharacterMetadata>;
  depth: number;
  data?: {[key: string]: any};
}

// Raw entity
interface RawDraftEntity {
  type: DraftEntityType;
  mutability: DraftEntityMutability;
  data: {[key: string]: any};
}

// Raw character metadata
interface RawDraftCharacterMetadata {
  style: Array<string>;
  entity: ?string;
}

// HTML conversion result
interface HTMLConversionResult {
  contentBlocks: Array<ContentBlock>;
  entityMap: any;
}

// Block render map for HTML conversion
type DraftBlockRenderMap = Immutable.Map<DraftBlockType, DraftBlockRenderConfig>;

interface DraftBlockRenderConfig {
  element: string;
  wrapper?: React.ComponentType<any>;
  aliasedElements?: Array<string>;
}

Install with Tessl CLI

npx tessl i tessl/npm-draft-js

docs

conversion-utilities.md

data-models.md

editor-components.md

entity-system.md

index.md

key-bindings-utilities.md

text-modification.md

tile.json