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-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
|
|
|
|
|
|
|
/**
|
|
|
|
* 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)
|
|
|
|
|
|
|
|
switch (key) {
|
|
|
|
case 'enter': {
|
2016-06-16 12:12:50 -07:00
|
|
|
e.preventDefault()
|
2016-06-18 18:21:21 -07:00
|
|
|
return state
|
|
|
|
.transform()
|
2016-06-23 15:39:44 -07:00
|
|
|
.splitBlock()
|
2016-06-18 18:21:21 -07:00
|
|
|
.apply()
|
2016-06-15 12:07:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
case 'backspace': {
|
|
|
|
// COMPAT: Windows has a special "cut" behavior for the shift key.
|
|
|
|
if (IS_WINDOWS && e.shiftKey) return
|
2016-06-16 12:12:50 -07:00
|
|
|
e.preventDefault()
|
2016-06-15 12:07:12 -07:00
|
|
|
return isWord(e)
|
2016-06-18 18:21:21 -07:00
|
|
|
? state
|
|
|
|
.transform()
|
|
|
|
.backspaceWord()
|
|
|
|
.apply()
|
|
|
|
: state
|
|
|
|
.transform()
|
|
|
|
.deleteBackward()
|
|
|
|
.apply()
|
2016-06-15 12:07:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
case 'delete': {
|
|
|
|
// COMPAT: Windows has a special "cut" behavior for the shift key.
|
|
|
|
if (IS_WINDOWS && e.shiftKey) return
|
2016-06-16 12:12:50 -07:00
|
|
|
e.preventDefault()
|
2016-06-15 12:07:12 -07:00
|
|
|
return isWord(e)
|
2016-06-18 18:21:21 -07:00
|
|
|
? state
|
|
|
|
.transform()
|
|
|
|
.deleteWord()
|
|
|
|
.apply()
|
|
|
|
: state
|
|
|
|
.transform()
|
|
|
|
.deleteForward()
|
|
|
|
.apply()
|
2016-06-15 12:07:12 -07:00
|
|
|
}
|
|
|
|
|
2016-06-21 10:43:04 -07:00
|
|
|
case 'b':
|
|
|
|
case 'i': {
|
|
|
|
if (!isCommand(e)) return
|
|
|
|
// COMPAT: Prevent the built-in contenteditable bold and italic
|
|
|
|
// shortcuts. They should be re-added at a higher level that is
|
|
|
|
// state-aware if you want to allow for them.
|
|
|
|
e.preventDefault()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-06-15 12:07:12 -07:00
|
|
|
case 'y': {
|
|
|
|
if (!isCtrl(e) || !IS_WINDOWS) return
|
2016-06-16 12:12:50 -07:00
|
|
|
e.preventDefault()
|
2016-06-18 18:21:21 -07:00
|
|
|
return state
|
|
|
|
.transform()
|
|
|
|
.redo()
|
2016-06-15 12:07:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
case 'z': {
|
|
|
|
if (!isCommand(e)) return
|
2016-06-16 12:12:50 -07:00
|
|
|
e.preventDefault()
|
2016-06-15 12:07:12 -07:00
|
|
|
return IS_MAC && e.shiftKey
|
2016-06-18 18:21:21 -07:00
|
|
|
? state
|
|
|
|
.transform()
|
|
|
|
.redo()
|
|
|
|
: state
|
|
|
|
.transform()
|
|
|
|
.undo()
|
2016-06-15 12:07:12 -07:00
|
|
|
}
|
|
|
|
}
|
2016-06-17 19:57:37 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Default `node` renderer.
|
|
|
|
*
|
|
|
|
* @param {Node} node
|
|
|
|
* @return {Component} component
|
|
|
|
*/
|
|
|
|
|
|
|
|
renderNode(node) {
|
|
|
|
return (props) => <div>{props.children}</div>
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Default `mark` renderer.
|
|
|
|
*
|
|
|
|
* @param {Mark} mark
|
|
|
|
* @return {Object} style
|
|
|
|
*/
|
|
|
|
|
|
|
|
renderMark(mark) {
|
|
|
|
return {}
|
2016-06-15 12:07:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-06-16 16:43:02 -07:00
|
|
|
* Does an `e` have the word-level modifier?
|
2016-06-15 12:07:12 -07:00
|
|
|
*
|
|
|
|
* @param {Event} e
|
|
|
|
* @return {Boolean}
|
|
|
|
*/
|
|
|
|
|
|
|
|
function isWord(e) {
|
|
|
|
if (IS_MAC && e.altKey) return true
|
|
|
|
if (e.ctrlKey) return true
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-06-16 16:43:02 -07:00
|
|
|
* Does an `e` have the control modifier?
|
2016-06-15 12:07:12 -07:00
|
|
|
*
|
|
|
|
* @param {Event} e
|
|
|
|
* @return {Boolean}
|
|
|
|
*/
|
|
|
|
|
|
|
|
function isCtrl(e) {
|
|
|
|
return e.ctrlKey && !e.altKey
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-06-16 16:43:02 -07:00
|
|
|
* Does an `e` have the option modifier?
|
2016-06-15 12:07:12 -07:00
|
|
|
*
|
|
|
|
* @param {Event} e
|
|
|
|
* @return {Boolean}
|
|
|
|
*/
|
|
|
|
|
|
|
|
function isOption(e) {
|
|
|
|
return IS_MAC && e.altKey
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Does an `e` have the shift modifier?
|
|
|
|
*
|
|
|
|
* @param {Event} e
|
|
|
|
* @return {Boolean}
|
|
|
|
*/
|
|
|
|
|
|
|
|
function isShift(e) {
|
|
|
|
return e.shiftKey
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-06-16 16:43:02 -07:00
|
|
|
* Does an `e` have the command modifier?
|
2016-06-15 12:07:12 -07:00
|
|
|
*
|
|
|
|
* @param {Event} e
|
|
|
|
* @return {Boolean}
|
|
|
|
*/
|
|
|
|
|
|
|
|
function isCommand(e) {
|
|
|
|
return IS_MAC
|
|
|
|
? e.metaKey && !e.altKey
|
|
|
|
: e.ctrlKey && !e.altKey
|
|
|
|
}
|