draft-js-code

Collection of utilities to make code blocks edition easy in DraftJS

Usage no npm install needed!

<script type="module">
  import draftJsCode from 'https://cdn.skypack.dev/draft-js-code';
</script>

README

draft-js-code

NPM version Coverage Status

draft-js-code is a collection of low-level utilities to make code block editing in DraftJS editors nicer.

It works well with draft-js-prism or draft-js-prism-plugin.

Demo: samypesse.github.io/draft-js-code/

Features

  • Indent with TAB
  • Insert new line with correct indentation with ENTER
  • Remove indentation with DELETE
  • Remove indentation with SHIFT+TAB (#6)
  • Handle input of pair characters like (), [], {}, "", etc. (#3)

Installation

$ npm install draft-js-code --save

API

CodeUtils.hasSelectionInBlock(editorState)

Returns true if user is editing a code block. You should call this method to encapsulate all other methods when limiting code edition behaviour to code-block.

CodeUtils.handleKeyCommand(editorState, command)

Handle key command for code blocks, returns a new EditorState or null.

CodeUtils.onTab(e, editorState)

Handle user pressing tab, to insert indentation, it returns a new EditorState.

CodeUtils.handleReturn(e, editorState)

Handle user pressing return, to insert a new line inside the code block, it returns a new EditorState.

Usage

import React from 'react';
import Draft from 'draft-js';
import CodeUtils from 'draft-js-code';

class Editor extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      editorState: Draft.EditorState.createEmpty()
    };
  }

  onChange = (editorState) => {
    this.setState({
      editorState
    })
  }

  handleKeyCommand = (command) => {
    const { editorState } = this.state;
    let newState;

    if (CodeUtils.hasSelectionInBlock(editorState)) {
      newState = CodeUtils.handleKeyCommand(editorState, command);
    }

    if (!newState) {
      newState = RichUtils.handleKeyCommand(editorState, command);
    }

    if (newState) {
      this.onChange(newState);
      return 'handled';
    }
    return 'not-handled';
  }

  keyBindingFn = (evt) => {
    const { editorState } = this.state;
    if (!CodeUtils.hasSelectionInBlock(editorState)) return Draft.getDefaultKeyBinding(evt);

    const command = CodeUtils.getKeyBinding(evt);

    return command || Draft.getDefaultKeyBinding(evt);
  }

  handleReturn = (evt) => {
    const { editorState } = this.state;
    if (!CodeUtils.hasSelectionInBlock(editorState)) return 'not-handled';

    this.onChange(CodeUtils.handleReturn(evt, editorState));
    return 'handled';
  }

  onTab = (evt) => {
    const { editorState } = this.state;
    if (!CodeUtils.hasSelectionInBlock(editorState)) return 'not-handled';

    this.onChange(CodeUtils.onTab(evt, editorState));
    return 'handled';
  }

  render() {
    return (
      <Draft.Editor
        editorState={this.state.editorState}
        onChange={this.onChange}
        keyBindingFn={this.keyBindingFn}
        handleKeyCommand={this.handleKeyCommand}
        handleReturn={this.handleReturn}
        onTab={this.onTab}
      />
    );
  }
}