2016-06-15 12:07:12 -07:00
|
|
|
|
2016-06-17 19:57:37 -07:00
|
|
|
import React from 'react'
|
2016-06-15 12:07:12 -07:00
|
|
|
import keycode from 'keycode'
|
2016-06-27 17:16:18 -07:00
|
|
|
import { isCommand, isCtrl, isWindowsCommand, isWord } from '../utils/event'
|
2016-06-23 15:39:44 -07:00
|
|
|
import { IS_WINDOWS, IS_MAC } from '../utils/environment'
|
2016-06-15 12:07:12 -07:00
|
|
|
|
|
|
|
/**
|
2016-06-17 18:20:26 -07:00
|
|
|
* Export.
|
2016-06-15 12:07:12 -07:00
|
|
|
*/
|
|
|
|
|
2016-06-17 18:20:26 -07:00
|
|
|
export default {
|
2016-06-15 12:07:12 -07:00
|
|
|
|
2016-06-24 10:46:01 -07:00
|
|
|
/**
|
|
|
|
* The core `onBeforeInput` handler.
|
|
|
|
*
|
2016-06-28 08:42:34 -07:00
|
|
|
* If the current selection is collapsed, we can insert the text natively and
|
|
|
|
* avoid a re-render, improving performance.
|
|
|
|
*
|
2016-06-24 10:46:01 -07:00
|
|
|
* @param {Event} e
|
|
|
|
* @param {State} state
|
|
|
|
* @param {Editor} editor
|
|
|
|
* @return {State or Null} newState
|
|
|
|
*/
|
|
|
|
|
|
|
|
onBeforeInput(e, state, editor) {
|
2016-06-28 08:42:34 -07:00
|
|
|
const isNative = state.isCollapsed
|
2016-06-24 10:46:01 -07:00
|
|
|
|
2016-06-28 08:42:34 -07:00
|
|
|
if (!isNative) e.preventDefault()
|
2016-06-24 10:46:01 -07:00
|
|
|
|
|
|
|
return state
|
|
|
|
.transform()
|
2016-06-28 08:42:34 -07:00
|
|
|
.insertText(e.data)
|
|
|
|
.apply({ isNative })
|
2016-06-24 10:46:01 -07:00
|
|
|
},
|
|
|
|
|
2016-06-15 12:07:12 -07:00
|
|
|
/**
|
|
|
|
* The core `onKeyDown` handler.
|
|
|
|
*
|
|
|
|
* @param {Event} e
|
2016-06-16 12:21:39 -07:00
|
|
|
* @param {State} state
|
2016-06-15 12:07:12 -07:00
|
|
|
* @param {Editor} editor
|
|
|
|
* @return {State or Null} newState
|
|
|
|
*/
|
|
|
|
|
2016-06-16 12:21:39 -07:00
|
|
|
onKeyDown(e, state, editor) {
|
2016-06-15 12:07:12 -07:00
|
|
|
const key = keycode(e.which)
|
2016-06-28 08:42:34 -07:00
|
|
|
const transform = state.transform()
|
2016-06-15 12:07:12 -07:00
|
|
|
|
|
|
|
switch (key) {
|
|
|
|
case 'enter': {
|
2016-06-28 08:42:34 -07:00
|
|
|
return transform.splitBlock().apply()
|
2016-06-15 12:07:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
case 'backspace': {
|
|
|
|
return isWord(e)
|
2016-06-28 08:42:34 -07:00
|
|
|
? transform.backspaceWord().apply()
|
|
|
|
: transform.deleteBackward().apply()
|
2016-06-15 12:07:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
case 'delete': {
|
|
|
|
return isWord(e)
|
2016-06-28 08:42:34 -07:00
|
|
|
? transform.deleteWord().apply()
|
|
|
|
: transform.deleteForward().apply()
|
2016-06-15 12:07:12 -07:00
|
|
|
}
|
|
|
|
|
2016-06-30 14:37:29 -07:00
|
|
|
case 'up': {
|
|
|
|
if (state.isExpanded) return
|
|
|
|
const first = state.blocks.first()
|
|
|
|
if (!first || !first.isVoid) return
|
|
|
|
e.preventDefault()
|
|
|
|
return transform.moveToEndOfPreviousBlock().apply()
|
|
|
|
}
|
|
|
|
|
|
|
|
case 'down': {
|
|
|
|
if (state.isExpanded) return
|
|
|
|
const first = state.blocks.first()
|
|
|
|
if (!first || !first.isVoid) return
|
|
|
|
e.preventDefault()
|
|
|
|
return transform.moveToStartOfNextBlock().apply()
|
|
|
|
}
|
|
|
|
|
|
|
|
case 'left': {
|
|
|
|
if (state.isExpanded) return
|
|
|
|
const node = state.blocks.first() || state.inlines.first()
|
|
|
|
if (!node || !node.isVoid) return
|
|
|
|
e.preventDefault()
|
|
|
|
return transform.moveToEndOfPreviousText().apply()
|
|
|
|
}
|
|
|
|
|
|
|
|
case 'right': {
|
|
|
|
if (state.isExpanded) return
|
|
|
|
const node = state.blocks.first() || state.inlines.first()
|
|
|
|
if (!node || !node.isVoid) return
|
|
|
|
e.preventDefault()
|
|
|
|
return transform.moveToStartOfNextText().apply()
|
|
|
|
}
|
|
|
|
|
2016-06-15 12:07:12 -07:00
|
|
|
case 'y': {
|
2016-06-27 17:16:18 -07:00
|
|
|
if (!isWindowsCommand(e)) return
|
2016-06-28 08:42:34 -07:00
|
|
|
return transform.redo()
|
2016-06-15 12:07:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
case 'z': {
|
|
|
|
if (!isCommand(e)) return
|
|
|
|
return IS_MAC && e.shiftKey
|
2016-06-28 08:42:34 -07:00
|
|
|
? transform.redo()
|
|
|
|
: transform.undo()
|
2016-06-15 12:07:12 -07:00
|
|
|
}
|
|
|
|
}
|
2016-06-17 19:57:37 -07:00
|
|
|
},
|
|
|
|
|
2016-06-24 12:06:59 -07:00
|
|
|
/**
|
|
|
|
* The core `onPaste` handler.
|
|
|
|
*
|
|
|
|
* @param {Event} e
|
|
|
|
* @param {Object} paste
|
|
|
|
* @param {State} state
|
|
|
|
* @param {Editor} editor
|
|
|
|
* @return {State or Null} newState
|
|
|
|
*/
|
|
|
|
|
|
|
|
onPaste(e, paste, state, editor) {
|
|
|
|
if (paste.type == 'files') return
|
|
|
|
|
|
|
|
let transform = state.transform()
|
|
|
|
|
|
|
|
paste.text
|
|
|
|
.split('\n')
|
|
|
|
.forEach((block, i) => {
|
|
|
|
if (i > 0) transform = transform.splitBlock()
|
|
|
|
transform = transform.insertText(block)
|
|
|
|
})
|
|
|
|
|
|
|
|
return transform.apply()
|
|
|
|
},
|
|
|
|
|
2016-06-17 19:57:37 -07:00
|
|
|
/**
|
|
|
|
* Default `node` renderer.
|
|
|
|
*
|
|
|
|
* @param {Node} node
|
|
|
|
* @return {Component} component
|
|
|
|
*/
|
|
|
|
|
|
|
|
renderNode(node) {
|
2016-06-28 08:42:34 -07:00
|
|
|
return node.kind == 'block'
|
|
|
|
? (props) => <div>{props.children}</div>
|
|
|
|
: (props) => <span>{props.children}</span>
|
2016-06-17 19:57:37 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Default `mark` renderer.
|
|
|
|
*
|
|
|
|
* @param {Mark} mark
|
|
|
|
* @return {Object} style
|
|
|
|
*/
|
|
|
|
|
|
|
|
renderMark(mark) {
|
|
|
|
return {}
|
2016-06-15 12:07:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|