1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-02-24 09:13:24 +01:00
slate/lib/plugins/core.js

197 lines
4.3 KiB
JavaScript
Raw Normal View History

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-07-06 14:48:40 -07:00
/**
* Default block renderer.
*/
const DEFAULT_BLOCK = props => <div>{props.children}</div>
/**
* Default inline renderer.
*
* @type {Component}
*/
const DEFAULT_INLINE = props => <span>{props.children}</span>
/**
* Default mark renderer.
*
* @type {Object}
*/
const DEFAULT_MARK = {}
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 `onBeforeInput` handler.
*
* If the current selection is expanded, we have to re-render.
*
* If the next state resolves a new list of decorations for any of its text
* nodes, we have to re-render.
*
* Otherwise, we can allow the default, native text insertion, avoiding a
* re-render for improved performance.
2016-06-28 08:42:34 -07:00
*
* @param {Event} e
* @param {State} state
* @param {Editor} editor
* @return {State or Null} newState
*/
onBeforeInput(e, state, editor) {
const transform = state.transform().insertText(e.data)
const synthetic = transform.apply()
const resolved = editor.resolveState(synthetic)
const isSynthenic = (
state.isExpanded ||
!resolved.equals(synthetic)
)
if (isSynthenic) e.preventDefault()
return isSynthenic
? synthetic
: transform.apply({ isNative: true })
},
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
/**
2016-07-06 14:48:40 -07:00
* The core `onPaste` handler, which treats everything as plain text.
2016-06-24 12:06:59 -07:00
*
* @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((line, i) => {
2016-06-24 12:06:59 -07:00
if (i > 0) transform = transform.splitBlock()
transform = transform.insertText(line)
2016-06-24 12:06:59 -07:00
})
return transform.apply()
},
2016-06-17 19:57:37 -07:00
/**
2016-07-06 14:48:40 -07:00
* The core `node` renderer, which uses plain `<div>` or `<span>` depending on
* what kind of node it is.
2016-06-17 19:57:37 -07:00
*
* @param {Node} node
* @return {Component} component
*/
renderNode(node) {
2016-06-28 08:42:34 -07:00
return node.kind == 'block'
2016-07-06 14:48:40 -07:00
? DEFAULT_BLOCK
: DEFAULT_INLINE
2016-06-17 19:57:37 -07:00
},
/**
2016-07-06 14:48:40 -07:00
* The core `mark` renderer, with no styles.
2016-06-17 19:57:37 -07:00
*
* @param {Mark} mark
* @return {Object} style
*/
renderMark(mark) {
2016-07-06 14:48:40 -07:00
return DEFAULT_MARK
2016-06-15 12:07:12 -07:00
}
}