hunk.code_window:       )
       }
       // Save the new operations.
       if (save || !previous) {
         this.save({ merge })
       }
  
hunk.labels: keep keep keep replace replace replace keep keep
hunk.after_edit:     // If the save flag isn't set, determine whether we should save.
       if (save == null) {
         save = !isOnlySelections(operations)
  
hunk.file_path: src/models/transform.js
hunk.type: replace
file: 
  import { Editor, Mark, Raw } from '../../..'
  import React from 'react'
  import initialState from './state.json'
  
  /**
   * Define the default node type.
   */
  
  const DEFAULT_NODE = 'paragraph'
  
  /**
   * Define a schema.
   *
   * @type {Object}
   */
  
  const schema = {
    nodes: {
      'block-quote': props => <blockquote {...props.attributes}>{props.children}</blockquote>,
      'bulleted-list': props => <ul {...props.attributes}>{props.children}</ul>,
      'heading-one': props => <h1 {...props.attributes}>{props.children}</h1>,
      'heading-two': props => <h2 {...props.attributes}>{props.children}</h2>,
      'list-item': props => <li {...props.attributes}>{props.children}</li>,
      'numbered-list': props => <ol {...props.attributes}>{props.children}</ol>
    },
    marks: {
      bold: {
        fontWeight: 'bold'
      },
      code: {
        fontFamily: 'monospace',
        backgroundColor: '#eee',
        padding: '3px',
        borderRadius: '4px'
      },
      italic: {
        fontStyle: 'italic'
      },
      underlined: {
        textDecoration: 'underline'
      }
    }
  }
  
  /**
   * The rich text example.
   *
   * @type {Component}
   */
  
  class RichText extends React.Component {
  
    /**
     * Deserialize the initial editor state.
     *
     * @type {Object}
     */
  
    state = {
      state: Raw.deserialize(initialState, { terse: true })
    };
  
    /**
     * Check if the current selection has a mark with `type` in it.
     *
     * @param {String} type
     * @return {Boolean}
     */
  
    hasMark = (type) => {
      const { state } = this.state
      return state.marks.some(mark => mark.type == type)
    }
  
    /**
     * Check if the any of the currently selected blocks are of `type`.
     *
     * @param {String} type
     * @return {Boolean}
     */
  
    hasBlock = (type) => {
      const { state } = this.state
      return state.blocks.some(node => node.type == type)
    }
  
    /**
     * On change, save the new state.
     *
     * @param {State} state
     */
  
    onChange = (state) => {
      this.setState({ state })
    }
  
    /**
     * On key down, if it's a formatting command toggle a mark.
     *
     * @param {Event} e
     * @param {Object} data
     * @param {State} state
     * @return {State}
     */
  
    onKeyDown = (e, data, state) => {
      if (!data.isMod) return
      let mark
  
      switch (data.key) {
        case 'b':
          mark = 'bold'
          break
        case 'i':
          mark = 'italic'
          break
        case 'u':
          mark = 'underlined'
          break
        case '`':
          mark = 'code'
          break
        default:
          return
      }
  
      state = state
        .transform()
        [this.hasMark(mark) ? 'removeMark' : 'addMark'](mark)
        .apply()
  
      e.preventDefault()
      return state
    }
  
    /**
     * When a mark button is clicked, toggle the current mark.
     *
     * @param {Event} e
     * @param {String} type
     */
  
    onClickMark = (e, type) => {
      e.preventDefault()
      const isActive = this.hasMark(type)
      let { state } = this.state
  
      state = state
        .transform()
        [isActive ? 'removeMark' : 'addMark'](type)
        .apply()
  
      this.setState({ state })
    }
  
    /**
     * When a block button is clicked, toggle the block type.
     *
     * @param {Event} e
     * @param {String} type
     */
  
    onClickBlock = (e, type) => {
      e.preventDefault()
      const isActive = this.hasBlock(type)
      let { state } = this.state
  
      let transform = state
        .transform()
        .setBlock(isActive ? 'paragraph' : type)
  
      // Handle the extra wrapping required for list buttons.
      if (type == 'bulleted-list' || type == 'numbered-list') {
        if (this.hasBlock('list-item')) {
          transform = transform
            .setBlock(DEFAULT_NODE)
            .unwrapBlock(type)
        } else {
          transform = transform
            .setBlock('list-item')
            .wrapBlock(type)
        }
      }
  
      // Handle everything but list buttons.
      else {
        transform = transform.setBlock(isActive ? DEFAULT_NODE : type)
      }
  
      state = transform.apply()
      this.setState({ state })
    }
  
    /**
     * Render.
     *
     * @return {Element}
     */
  
    render = () => {
      return (
        <div>
          {this.renderToolbar()}
          {this.renderEditor()}
        </div>
      )
    }
  
    /**
     * Render the toolbar.
     *
     * @return {Element}
     */
  
    renderToolbar = () => {
      return (
        <div className="menu toolbar-menu">
          {this.renderMarkButton('bold', 'format_bold')}
          {this.renderMarkButton('italic', 'format_italic')}
          {this.renderMarkButton('underlined', 'format_underlined')}
          {this.renderMarkButton('code', 'code')}
          {this.renderBlockButton('heading-one', 'looks_one')}
          {this.renderBlockButton('heading-two', 'looks_two')}
          {this.renderBlockButton('block-quote', 'format_quote')}
          {this.renderBlockButton('numbered-list', 'format_list_numbered')}
          {this.renderBlockButton('bulleted-list', 'format_list_bulleted')}
        </div>
      )
    }
  
    /**
     * Render a mark-toggling toolbar button.
     *
     * @param {String} type
     * @param {String} icon
     * @return {Element}
     */
  
    renderMarkButton = (type, icon) => {
      const isActive = this.hasMark(type)
      const onMouseDown = e => this.onClickMark(e, type)
  
      return (
        <span className="button" onMouseDown={onMouseDown} data-active={isActive}>
          <span className="material-icons">{icon}</span>
        </span>
      )
    }
  
    /**
     * Render a block-toggling toolbar button.
     *
     * @param {String} type
     * @param {String} icon
     * @return {Element}
     */
  
    renderBlockButton = (type, icon) => {
      const isActive = this.hasBlock(type)
      const onMouseDown = e => this.onClickBlock(e, type)
  
      return (
        <span className="button" onMouseDown={onMouseDown} data-active={isActive}>
          <span className="material-icons">{icon}</span>
        </span>
      )
    }
  
    /**
     * Render the Slate editor.
     *
     * @return {Element}
     */
  
    renderEditor = () => {
      return (
        <div className="editor">
          <Editor
            placeholder={'Enter some rich text...'}
            schema={schema}
            state={this.state.state}
            onChange={this.onChange}
            onKeyDown={this.onKeyDown}
          />
        </div>
      )
    }
  
  }
  
  /**
   * Export.
   */
  
  export default RichText
  