mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-04-21 13:51:59 +02:00
fix prevent default on key down
This commit is contained in:
parent
5d21a315f7
commit
0c22e6172b
@ -4,6 +4,7 @@ import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import Text from './text'
|
||||
import keycode from 'keycode'
|
||||
import { isCommand, isWindowsCommand } from '../utils/event'
|
||||
|
||||
/**
|
||||
* Content.
|
||||
@ -64,6 +65,31 @@ class Content extends React.Component {
|
||||
this.props[name](e)
|
||||
}
|
||||
|
||||
/**
|
||||
* On key down, prevent the default behavior of certain commands that will
|
||||
* leave the editor in an out-of-sync state, then bubble up.
|
||||
*
|
||||
* @param {Event} e
|
||||
*/
|
||||
|
||||
onKeyDown(e) {
|
||||
const key = keycode(e.which)
|
||||
|
||||
if (
|
||||
(key == 'enter') ||
|
||||
(key == 'backspace') ||
|
||||
(key == 'delete') ||
|
||||
(key == 'b' && isCommand(e)) ||
|
||||
(key == 'i' && isCommand(e)) ||
|
||||
(key == 'y' && isWindowsCommand(e)) ||
|
||||
(key == 'z' && isCommand(e))
|
||||
) {
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
this.props.onKeyDown(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* On paste, determine the type and bubble up.
|
||||
*
|
||||
@ -110,8 +136,7 @@ class Content extends React.Component {
|
||||
let { document, selection } = state
|
||||
const native = window.getSelection()
|
||||
|
||||
// No selection is active, so unset `isFocused`.
|
||||
if (!native.rangeCount && selection.isFocused) {
|
||||
if (!native.rangeCount) {
|
||||
selection = selection.merge({ isFocused: false })
|
||||
state = state.merge({ selection })
|
||||
this.onChange(state)
|
||||
@ -122,24 +147,16 @@ class Content extends React.Component {
|
||||
const { anchorNode, anchorOffset, focusNode, focusOffset } = native
|
||||
const anchor = OffsetKey.findPoint(anchorNode, anchorOffset)
|
||||
const focus = OffsetKey.findPoint(focusNode, focusOffset)
|
||||
const edges = document.filterDescendants((node) => {
|
||||
return node.key == anchor.key || node.key == focus.key
|
||||
})
|
||||
|
||||
const isBackward = (
|
||||
(edges.size == 2 && edges.first().key == focus.key) ||
|
||||
(edges.size == 1 && anchor.offset > focus.offset)
|
||||
)
|
||||
|
||||
selection = selection.merge({
|
||||
anchorKey: anchor.key,
|
||||
anchorOffset: anchor.offset,
|
||||
focusKey: focus.key,
|
||||
focusOffset: focus.offset,
|
||||
isBackward: isBackward,
|
||||
isFocused: true
|
||||
})
|
||||
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
this.onChange(state)
|
||||
}
|
||||
@ -167,11 +184,11 @@ class Content extends React.Component {
|
||||
<div
|
||||
contentEditable suppressContentEditableWarning
|
||||
style={style}
|
||||
onKeyDown={e => this.onKeyDown(e)}
|
||||
onSelect={e => this.onSelect(e)}
|
||||
onPaste={e => this.onPaste(e)}
|
||||
onCopy={e => this.onEvent('onCopy', e)}
|
||||
onCut={e => this.onEvent('onCut', e)}
|
||||
onKeyDown={e => this.onEvent('onKeyDown', e)}
|
||||
onBeforeInput={e => this.onEvent('onBeforeInput', e)}
|
||||
>
|
||||
{children}
|
||||
|
@ -1,6 +1,7 @@
|
||||
|
||||
import React from 'react'
|
||||
import keycode from 'keycode'
|
||||
import { isCommand, isCtrl, isWindowsCommand, isWord } from '../utils/event'
|
||||
import { IS_WINDOWS, IS_MAC } from '../utils/environment'
|
||||
|
||||
/**
|
||||
@ -71,7 +72,6 @@ export default {
|
||||
|
||||
switch (key) {
|
||||
case 'enter': {
|
||||
e.preventDefault()
|
||||
return state
|
||||
.transform()
|
||||
.splitBlock()
|
||||
@ -79,9 +79,6 @@ export default {
|
||||
}
|
||||
|
||||
case 'backspace': {
|
||||
// COMPAT: Windows has a special "cut" behavior for the shift key.
|
||||
if (IS_WINDOWS && e.shiftKey) return
|
||||
e.preventDefault()
|
||||
return isWord(e)
|
||||
? state
|
||||
.transform()
|
||||
@ -94,9 +91,6 @@ export default {
|
||||
}
|
||||
|
||||
case 'delete': {
|
||||
// COMPAT: Windows has a special "cut" behavior for the shift key.
|
||||
if (IS_WINDOWS && e.shiftKey) return
|
||||
e.preventDefault()
|
||||
return isWord(e)
|
||||
? state
|
||||
.transform()
|
||||
@ -108,19 +102,8 @@ export default {
|
||||
.apply()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
case 'y': {
|
||||
if (!isCtrl(e) || !IS_WINDOWS) return
|
||||
e.preventDefault()
|
||||
if (!isWindowsCommand(e)) return
|
||||
return state
|
||||
.transform()
|
||||
.redo()
|
||||
@ -128,7 +111,6 @@ export default {
|
||||
|
||||
case 'z': {
|
||||
if (!isCommand(e)) return
|
||||
e.preventDefault()
|
||||
return IS_MAC && e.shiftKey
|
||||
? state
|
||||
.transform()
|
||||
@ -206,61 +188,3 @@ export default {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Does an `e` have the word-level modifier?
|
||||
*
|
||||
* @param {Event} e
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
function isWord(e) {
|
||||
if (IS_MAC && e.altKey) return true
|
||||
if (e.ctrlKey) return true
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Does an `e` have the control modifier?
|
||||
*
|
||||
* @param {Event} e
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
function isCtrl(e) {
|
||||
return e.ctrlKey && !e.altKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Does an `e` have the option modifier?
|
||||
*
|
||||
* @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
|
||||
}
|
||||
|
||||
/**
|
||||
* Does an `e` have the command modifier?
|
||||
*
|
||||
* @param {Event} e
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
function isCommand(e) {
|
||||
return IS_MAC
|
||||
? e.metaKey && !e.altKey
|
||||
: e.ctrlKey && !e.altKey
|
||||
}
|
||||
|
@ -2,27 +2,17 @@
|
||||
import browser from 'detect-browser'
|
||||
import Parser from 'ua-parser-js'
|
||||
|
||||
/**
|
||||
* Read the environment.
|
||||
*/
|
||||
|
||||
const ENVIRONMENT = process.browser
|
||||
? {
|
||||
IS_ANDROID: browser.name === 'android',
|
||||
IS_CHROME: browser.name === 'chrome',
|
||||
IS_EDGE: browser.name === 'edge',
|
||||
IS_FIREFOX: browser.name === 'firefox',
|
||||
IS_IE: browser.name === 'ie',
|
||||
IS_IOS: browser.name === 'ios',
|
||||
IS_MAC: new Parser().getOS().name === 'Mac OS',
|
||||
IS_UBUNTU: new Parser().getOS().name === 'Ubuntu',
|
||||
IS_SAFARI: browser.name === 'safari',
|
||||
IS_WINDOWS: new Parser().getOS().name.includes('Windows')
|
||||
}
|
||||
: {}
|
||||
|
||||
/**
|
||||
* Export.
|
||||
*/
|
||||
|
||||
export default ENVIRONMENT
|
||||
export const IS_ANDROID = process.browser && browser.name === 'android'
|
||||
export const IS_CHROME = process.browser && browser.name === 'chrome'
|
||||
export const IS_EDGE = process.browser && browser.name === 'edge'
|
||||
export const IS_FIREFOX = process.browser && browser.name === 'firefox'
|
||||
export const IS_IE = process.browser && browser.name === 'ie'
|
||||
export const IS_IOS = process.browser && browser.name === 'ios'
|
||||
export const IS_MAC = process.browser && new Parser().getOS().name === 'Mac OS'
|
||||
export const IS_SAFARI = process.browser && browser.name === 'safari'
|
||||
export const IS_UBUNTU = process.browser && new Parser().getOS().name === 'Ubuntu'
|
||||
export const IS_WINDOWS = process.browser && new Parser().getOS().name.includes('Windows')
|
||||
|
83
lib/utils/event.js
Normal file
83
lib/utils/event.js
Normal file
@ -0,0 +1,83 @@
|
||||
|
||||
import { IS_MAC, IS_WINDOWS } from './environment'
|
||||
|
||||
/**
|
||||
* Does an `e` have the word-level modifier?
|
||||
*
|
||||
* @param {Event} e
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
export function isWord(e) {
|
||||
return IS_MAC
|
||||
? e.altKey
|
||||
: e.ctrlKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Does an `e` have the control modifier?
|
||||
*
|
||||
* @param {Event} e
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
export function isCtrl(e) {
|
||||
return e.ctrlKey && !e.altKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Does an `e` have the option modifier?
|
||||
*
|
||||
* @param {Event} e
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
export function isOption(e) {
|
||||
return IS_MAC && e.altKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Does an `e` have the shift modifier?
|
||||
*
|
||||
* @param {Event} e
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
export function isShift(e) {
|
||||
return e.shiftKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Does an `e` have the command modifier?
|
||||
*
|
||||
* @param {Event} e
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
export function isCommand(e) {
|
||||
return IS_MAC
|
||||
? e.metaKey && !e.altKey
|
||||
: e.ctrlKey && !e.altKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Does an `e` have the Mac command modifier?
|
||||
*
|
||||
* @param {Event} e
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
export function isMacCommand(e) {
|
||||
return IS_MAC && isCommand(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Does an `e` have the Windows command modifier?
|
||||
*
|
||||
* @param {Event} e
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
export function isWindowsCommand(e) {
|
||||
return IS_WINDOWS && isCommand(e)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user