1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-16 12:14:14 +02:00

refactor slate-hotkeys, fix deleting at start of block (#2048)

This commit is contained in:
Ian Storm Taylor
2018-08-07 15:58:33 -07:00
committed by GitHub
parent 3eabdea8d6
commit fd9243b8f5
6 changed files with 101 additions and 120 deletions

View File

@@ -4,6 +4,14 @@ This document maintains a list of changes to the `slate-hotkeys` package with ea
---
### `0.2.0` — August 7, 2018
###### BREAKING
**Some hotkey checkers have changed or been removed.** Please check the source to see the changes, sorry for the hassle. This was needed to cleanup the behavior and get this package to not be leaky in terms of what checkers it exposed.
---
### `0.1.0` — April 5, 2018
:tada:

View File

@@ -13,7 +13,7 @@
"lib/"
],
"dependencies": {
"is-hotkey": "^0.1.1",
"is-hotkey": "^0.1.3",
"slate-dev-environment": "^0.1.4"
},
"scripts": {

View File

@@ -2,104 +2,80 @@ import { isKeyHotkey } from 'is-hotkey'
import { IS_IOS, IS_MAC } from 'slate-dev-environment'
/**
* Is Apple?
* Hotkey mappings for each platform.
*
* @type {Boolean}
* @type {Object}
*/
const IS_APPLE = IS_IOS || IS_MAC
const HOTKEYS = {
bold: 'mod+b',
compose: ['down', 'left', 'right', 'up', 'backspace', 'enter'],
moveBackward: 'mod?+ctrl?+alt?+left',
moveForward: 'mod?+ctrl?+alt?+right',
deleteBackward: 'shift?+backspace',
deleteForward: 'shift?+delete',
extendBackward: 'shift+left',
extendForward: 'shift+right',
italic: 'mod+i',
splitBlock: 'shift?+enter',
undo: 'mod+z',
}
const APPLE_HOTKEYS = {
moveLineBackward: 'opt+up',
moveLineForward: 'opt+down',
deleteBackward: ['ctrl+backspace', 'ctrl+h'],
deleteForward: ['ctrl+delete', 'ctrl+d'],
deleteLineBackward: 'cmd+shift?+backspace',
deleteLineForward: ['cmd+shift?+delete', 'ctrl+k'],
deleteWordBackward: 'opt+shift?+backspace',
deleteWordForward: 'opt+shift?+delete',
extendLineBackward: 'opt+shift+up',
extendLineForward: 'opt+shift+down',
redo: 'cmd+shift+z',
transposeCharacter: 'ctrl+t',
}
const WINDOWS_HOTKEYS = {
deleteWordBackward: 'ctrl+shift?+backspace',
deleteWordForward: 'ctrl+shift?+delete',
redo: 'ctrl+y',
}
/**
* Hotkeys.
*
* @type {Function}
* @type {Object}
*/
const isBold = isKeyHotkey('mod+b')
const isItalic = isKeyHotkey('mod+i')
const Hotkeys = {}
const isEnter = isKeyHotkey('enter')
const isShiftEnter = isKeyHotkey('shift+enter')
const isSplitBlock = e => isEnter(e) || isShiftEnter(e)
const IS_APPLE = IS_IOS || IS_MAC
const IS_WINDOWS = !IS_APPLE
const KEYS = []
.concat(Object.keys(HOTKEYS))
.concat(Object.keys(APPLE_HOTKEYS))
.concat(Object.keys(WINDOWS_HOTKEYS))
const isBackspace = isKeyHotkey('backspace')
const isShiftBackspace = isKeyHotkey('shift+backspace')
const isDelete = isKeyHotkey('delete')
const isShiftDelete = isKeyHotkey('shift+delete')
const isDeleteBackward = e => isBackspace(e) || isShiftBackspace(e)
const isDeleteForward = e => isDelete(e) || isShiftDelete(e)
KEYS.forEach(key => {
const method = `is${key[0].toUpperCase()}${key.slice(1)}`
if (Hotkeys[method]) return
const isDeleteCharBackwardMac = isKeyHotkey('ctrl+h')
const isDeleteCharForwardMac = isKeyHotkey('ctrl+d')
const isDeleteCharBackward = e =>
isDeleteBackward(e) || (IS_APPLE && isDeleteCharBackwardMac(e))
const isDeleteCharForward = e =>
isDeleteForward(e) || (IS_APPLE && isDeleteCharForwardMac(e))
const generic = HOTKEYS[key]
const apple = APPLE_HOTKEYS[key]
const windows = WINDOWS_HOTKEYS[key]
const isDeleteLineBackwardMac = e =>
isKeyHotkey('cmd+shift+backspace', e) || isKeyHotkey('cmd+backspace', e)
const isDeleteLineForwardMac = isKeyHotkey('ctrl+k')
const isDeleteLineBackward = e => IS_APPLE && isDeleteLineBackwardMac(e)
const isDeleteLineForward = e => IS_APPLE && isDeleteLineForwardMac(e)
const isGeneric = generic && isKeyHotkey(generic)
const isApple = apple && isKeyHotkey(apple)
const isWindows = windows && isKeyHotkey(windows)
const isDeleteWordBackwardMac = e =>
isKeyHotkey('shift+option+backspace', e) || isKeyHotkey('option+backspace', e)
const isDeleteWordBackwardPC = isKeyHotkey('ctrl+backspace')
const isDeleteWordForwardMac = e =>
isKeyHotkey('shift+option+delete', e) || isKeyHotkey('option+delete', e)
const isDeleteWordForwardPC = isKeyHotkey('ctrl+delete')
const isDeleteWordBackward = e =>
IS_APPLE ? isDeleteWordBackwardMac(e) : isDeleteWordBackwardPC(e)
const isDeleteWordForward = e =>
IS_APPLE ? isDeleteWordForwardMac(e) : isDeleteWordForwardPC(e)
const isExtendCharForward = isKeyHotkey('shift+right')
const isExtendCharBackward = isKeyHotkey('shift+left')
const isRightArrow = isKeyHotkey('right')
const isLeftArrow = isKeyHotkey('left')
const isCollapseCharForward = e => isRightArrow(e) && !isExtendCharForward(e)
const isCollapseCharBackward = e => isLeftArrow(e) && !isExtendCharBackward(e)
const isCollapseLineBackwardMac = isKeyHotkey('option+up')
const isCollapseLineForwardMac = isKeyHotkey('option+down')
const isCollapseLineBackward = e => IS_APPLE && isCollapseLineBackwardMac(e)
const isCollapseLineForward = e => IS_APPLE && isCollapseLineForwardMac(e)
const isExtendLineBackwardMac = isKeyHotkey('option+shift+up')
const isExtendLineForwardMac = isKeyHotkey('option+shift+down')
const isExtendLineBackward = e => IS_APPLE && isExtendLineBackwardMac(e)
const isExtendLineForward = e => IS_APPLE && isExtendLineForwardMac(e)
const isUndo = isKeyHotkey('mod+z')
const isRedoMac = isKeyHotkey('mod+shift+z')
const isRedoPC = isKeyHotkey('mod+y')
const isRedo = e => (IS_APPLE ? isRedoMac(e) : isRedoPC(e))
const isTransposeCharacterMac = isKeyHotkey('ctrl+t')
const isTransposeCharacter = e => IS_APPLE && isTransposeCharacterMac(e)
const isContentEditable = e =>
isBold(e) ||
isDeleteCharBackward(e) ||
isDeleteCharForward(e) ||
isDeleteLineBackward(e) ||
isDeleteLineForward(e) ||
isDeleteWordBackward(e) ||
isDeleteWordForward(e) ||
isItalic(e) ||
isRedo(e) ||
isSplitBlock(e) ||
isTransposeCharacter(e) ||
isUndo(e)
const isComposing = e =>
e.key == 'ArrowDown' ||
e.key == 'ArrowLeft' ||
e.key == 'ArrowRight' ||
e.key == 'ArrowUp' ||
e.key == 'Backspace' ||
e.key == 'Enter'
Hotkeys[method] = event => {
if (isGeneric && isGeneric(event)) return true
if (IS_APPLE && isApple && isApple(event)) return true
if (IS_WINDOWS && isWindows && isWindows(event)) return true
return false
}
})
/**
* Export.
@@ -107,26 +83,4 @@ const isComposing = e =>
* @type {Object}
*/
export default {
isBold,
isCollapseCharBackward,
isCollapseCharForward,
isCollapseLineBackward,
isCollapseLineForward,
isComposing,
isContentEditable,
isDeleteCharBackward,
isDeleteCharForward,
isDeleteLineBackward,
isDeleteLineForward,
isDeleteWordBackward,
isDeleteWordForward,
isExtendCharBackward,
isExtendCharForward,
isExtendLineBackward,
isExtendLineForward,
isItalic,
isRedo,
isSplitBlock,
isUndo,
}
export default Hotkeys

View File

@@ -377,11 +377,11 @@ function AfterPlugin() {
: change.splitBlock()
}
if (Hotkeys.isDeleteCharBackward(event) && !IS_IOS) {
if (Hotkeys.isDeleteBackward(event) && !IS_IOS) {
return change.deleteCharBackward()
}
if (Hotkeys.isDeleteCharForward(event) && !IS_IOS) {
if (Hotkeys.isDeleteForward(event) && !IS_IOS) {
return change.deleteCharForward()
}
@@ -412,12 +412,12 @@ function AfterPlugin() {
// COMPAT: Certain browsers don't handle the selection updates properly. In
// Chrome, the selection isn't properly extended. And in Firefox, the
// selection isn't properly collapsed. (2017/10/17)
if (Hotkeys.isCollapseLineBackward(event)) {
if (Hotkeys.isMoveLineBackward(event)) {
event.preventDefault()
return change.moveToStartOfBlock()
}
if (Hotkeys.isCollapseLineForward(event)) {
if (Hotkeys.isMoveLineForward(event)) {
event.preventDefault()
return change.moveToEndOfBlock()
}
@@ -435,7 +435,7 @@ function AfterPlugin() {
// COMPAT: If a void node is selected, or a zero-width text node adjacent to
// an inline is selected, we need to handle these hotkeys manually because
// browsers won't know what to do.
if (Hotkeys.isCollapseCharBackward(event)) {
if (Hotkeys.isMoveBackward(event)) {
const { document, isInVoid, previousText, startText } = value
const isPreviousInVoid =
previousText && document.hasVoidParent(previousText.key)
@@ -446,7 +446,7 @@ function AfterPlugin() {
}
}
if (Hotkeys.isCollapseCharForward(event)) {
if (Hotkeys.isMoveForward(event)) {
const { document, isInVoid, nextText, startText } = value
const isNextInVoid = nextText && document.hasVoidParent(nextText.key)
@@ -456,7 +456,7 @@ function AfterPlugin() {
}
}
if (Hotkeys.isExtendCharBackward(event)) {
if (Hotkeys.isExtendBackward(event)) {
const { document, isInVoid, previousText, startText } = value
const isPreviousInVoid =
previousText && document.hasVoidParent(previousText.key)
@@ -467,7 +467,7 @@ function AfterPlugin() {
}
}
if (Hotkeys.isExtendCharForward(event)) {
if (Hotkeys.isExtendForward(event)) {
const { document, isInVoid, nextText, startText } = value
const isNextInVoid = nextText && document.hasVoidParent(nextText.key)

View File

@@ -387,13 +387,28 @@ function BeforePlugin() {
// typing. However, certain characters also move the selection before
// we're able to handle it, so prevent their default behavior.
if (isComposing) {
if (Hotkeys.isComposing(event)) event.preventDefault()
if (Hotkeys.isCompose(event)) event.preventDefault()
return true
}
// Certain hotkeys have native behavior in contenteditable elements which
// will cause our value to be out of sync, so prevent them.
if (Hotkeys.isContentEditable(event) && !IS_IOS) {
// Certain hotkeys have native editing behaviors in `contenteditable`
// elements which will change the DOM and cause our value to be out of sync,
// so they need to always be prevented.
if (
!IS_IOS &&
(Hotkeys.isBold(event) ||
Hotkeys.isDeleteBackward(event) ||
Hotkeys.isDeleteForward(event) ||
Hotkeys.isDeleteLineBackward(event) ||
Hotkeys.isDeleteLineForward(event) ||
Hotkeys.isDeleteWordBackward(event) ||
Hotkeys.isDeleteWordForward(event) ||
Hotkeys.isItalic(event) ||
Hotkeys.isRedo(event) ||
Hotkeys.isSplitBlock(event) ||
Hotkeys.isTransposeCharacter(event) ||
Hotkeys.isUndo(event))
) {
event.preventDefault()
}

View File

@@ -4706,6 +4706,10 @@ is-hotkey@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-hotkey/-/is-hotkey-0.1.1.tgz#b279a2fd108391be9aa93c6cb317f50357da549a"
is-hotkey@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/is-hotkey/-/is-hotkey-0.1.3.tgz#8a129eec16f3941bd4f37191e02b9c3e91950549"
is-in-browser@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835"