1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-17 20:51:20 +02:00

remove keyboard data.* properties (#1235)

* update examples and walkthroughs

* deprecate data keyboard properties

* update examples

* add is-hotkey to resources doc

* udpate docs

* update docs

* fix split-block test
This commit is contained in:
Ian Storm Taylor
2017-10-15 19:23:07 -07:00
committed by GitHub
parent c2ba87d327
commit f69d2c4a12
19 changed files with 200 additions and 296 deletions

View File

@@ -6,7 +6,8 @@ A few resources that are helpful for building with Slate.
## Libraries
- [`react-broadcast`] works well when you need to have your custom node components re-render based on state that lives outside the `document`. It's the same pattern that `react-router` uses to update `<Link>` components.
- [`is-hotkey`](https://github.com/ianstormtaylor/is-hotkey) is a simple way to check whether an `onKeyDown` handler should fire for a given hotkey, handling cross-platform concerns like <kbd>cmd</kbd> vs. <kbd>ctrl</kbd> keys for you automatically.
- [`react-broadcast`](https://github.com/ReactTraining/react-broadcast) works well when you need to have your custom node components re-render based on state that lives outside the `document`. It's the same pattern that `react-router` uses to update `<Link>` components.
## Tooling

View File

@@ -115,30 +115,6 @@ If no other plugin handles this event, it will be handled by the [Core plugin](.
This handler is called when any key is pressed in the `contenteditable` element, before any action is taken.
The `data` object contains the `key` which is a string name of the key that was pressed, as well as it's `code`. It also contains a series of helpful utility properties for determining hotkey logic. For example, `isCtrl` is true if the `control` key was pressed before.
```js
{
key: String,
code: Number,
isAlt: Boolean,
isCmd: Boolean,
isCtrl: Boolean,
isLine: Boolean,
isMeta: Boolean,
isMod: Boolean,
isModAlt: Boolean,
isShift: Boolean,
isWord: Boolean
}
```
The `isMod` boolean is `true` if the `control` key was pressed on Windows or the `command` key was pressed on Mac _without_ the `alt/option` key also being pressed. This is a convenience for adding hotkeys like `command+b`.
The `isModAlt` boolean is `true` if the `control` key was pressed on Windows or the `command` key was pressed on Mac _and_ the `alt/option` key was also being pressed. This is a convenience for secondary hotkeys like `command+option+1`.
The `isLine` and `isWord` booleans represent whether the "line modifier" or "word modifier" hotkeys are pressed when deleting or moving the cursor. For example, on a Mac `option + right` moves the cursor to the right one word at a time.
Make sure to `event.preventDefault()` if you do not want the default insertion behavior to occur! If no other plugin handles this event, it will be handled by the [Core plugin](./core.md).
### `onKeyUp`
@@ -146,8 +122,6 @@ Make sure to `event.preventDefault()` if you do not want the default insertion b
This handler is called when any key is released in the `contenteditable` element.
The `data` object contains the same information as the `data` object of `onKeyDown`.
### `onPaste`
`Function onPaste(event: Event, data: Object, change: Change, editor: Editor) => Change || Void`

View File

@@ -49,9 +49,9 @@ class App extends React.Component {
this.setState({ state })
}
// Define a new handler which prints the key code that was pressed.
// Define a new handler which prints the key that was pressed.
onKeyDown = (event, data, change) => {
console.log(event.which)
console.log(event.key)
}
render() {
@@ -85,8 +85,8 @@ class App extends React.Component {
}
onKeyDown = (event, data, change) => {
// Return with no changes if it's not the "7" key with shift pressed.
if (event.which != 55 || !event.shiftKey) return
// Return with no changes if it's not the "&" key.
if (event.key != '&') return
// Prevent the ampersand character from being inserted.
event.preventDefault()

View File

@@ -28,7 +28,7 @@ class App extends React.Component {
}
onKeyDown = (event, data, change) => {
if (event.which != 67 || !event.metaKey || !event.altKey) return
if (event.key != '`' || !event.metaKey) return
event.preventDefault()
const isCode = change.state.blocks.some(block => block.type == 'code')
@@ -72,16 +72,15 @@ class App extends React.Component {
if (!event.metaKey) return
// Decide what to do based on the key code...
switch (event.which) {
switch (event.key) {
// When "B" is pressed, add a "bold" mark to the text.
case 66: {
case 'b': {
event.preventDefault()
change.addMark('bold')
return true
}
// When "`" is pressed, keep our existing code block logic.
case 67: {
if (!event.altKey) return
case '`': {
const isCode = change.state.blocks.some(block => block.type == 'code')
event.preventDefault()
change.setBlock(isCode ? 'paragraph' : 'code')
@@ -148,14 +147,13 @@ class App extends React.Component {
onKeyDown = (event, data, change) => {
if (!event.metaKey) return
switch (event.which) {
case 66: {
switch (event.key) {
case 'b': {
event.preventDefault()
change.toggleMark('bold')
return true
}
case 67: {
if (!event.altKey) return
case '`': {
const isCode = change.state.blocks.some(block => block.type == 'code')
event.preventDefault()
state.setBlock(isCode ? 'paragraph' : 'code')

View File

@@ -23,10 +23,8 @@ class App extends React.Component {
}
onKeyDown = (event, data, change) => {
if (event.which != 55 || !event.shiftKey) return
if (event.key != '&') return
event.preventDefault()
change.insertText('and');
return true
}
@@ -87,10 +85,8 @@ class App extends React.Component {
}
onKeyDown = (event, data, change) => {
if (event.which != 55 || !event.shiftKey) return
if (event.key != '&') return
event.preventDefault()
change.insertText('and')
return true
}
@@ -110,7 +106,7 @@ class App extends React.Component {
}
```
Okay, but now we'll need a way for the user to actually turn a block into a code block. So let's change our `onKeyDown` function to add a `⌘-Alt-C` shortcut that does just that:
Okay, but now we'll need a way for the user to actually turn a block into a code block. So let's change our `onKeyDown` function to add a `⌘-\`` shortcut that does just that:
```js
function CodeNode(props) {
@@ -134,7 +130,7 @@ class App extends React.Component {
onKeyDown = (event, data, change) => {
// Return with no changes if it's not the "`" key with cmd/ctrl pressed.
if (event.which != 67 || !event.metaKey || !event.altKey) return
if (event.key != '`' || !event.metaKey) return
// Prevent the "`" from being inserted by default.
event.preventDefault()
@@ -158,9 +154,9 @@ class App extends React.Component {
}
```
Now, if you press `⌘-Alt-C`, the block your cursor is in should turn into a code block! Magic!
Now, if you press `⌘-\`` the block your cursor is in should turn into a code block! Magic!
But we forgot one thing. When you hit `⌘-Alt-C` again, it should change the code block back into a paragraph. To do that, we'll need to add a bit of logic to change the type we set based on whether any of the currently selected blocks are already a code block:
But we forgot one thing. When you hit `⌘-\`` again, it should change the code block back into a paragraph. To do that, we'll need to add a bit of logic to change the type we set based on whether any of the currently selected blocks are already a code block:
```js
function CodeNode(props) {
@@ -183,7 +179,7 @@ class App extends React.Component {
}
onKeyDown = (event, data, change) => {
if (event.which != 67 || !event.metaKey || !event.altKey) return
if (event.key != '`' || !event.metaKey) return
event.preventDefault()
@@ -209,7 +205,7 @@ class App extends React.Component {
}
```
And there you have it! If you press `⌘-Alt-C` while inside a code block, it should turn back into a paragraph!
And there you have it! If you press `⌘-\`` while inside a code block, it should turn back into a paragraph!
<br/>
<p align="center"><strong>Next:</strong><br/><a href="./applying-custom-formatting.md">Applying Custom Formatting</a></p>

View File

@@ -30,7 +30,7 @@ class App extends React.Component {
}
onKeyDown = (event, data, change) => {
if (!event.metaKey || event.which != 66) return
if (event.key != 'b' || !event.metaKey) return
event.preventDefault()
change.toggleMark('bold')
return true
@@ -50,12 +50,12 @@ class App extends React.Component {
}
```
Let's write a new function, that takes a set of options: the mark `type` to toggle and the key `code` to press.
Let's write a new function, that takes a set of options: the mark `type` to toggle and the `key` to press.
```js
function MarkHotkey(options) {
// Grab our options from the ones passed in.
const { type, code, isAltKey = false } = options
const { type, key } = options
}
```
@@ -67,13 +67,13 @@ In this case our plugin object will have one property: a `onKeyDown` handler, wi
```js
function MarkHotkey(options) {
const { type, code, isAltKey = false } = options
const { type, key } = options
// Return our "plugin" object, containing the `onKeyDown` handler.
return {
onKeyDown(event, data, change) {
// Check that the key pressed matches our `code` option.
if (!event.metaKey || event.which != code || event.altKey != isAltKey) return
// Check that the key pressed matches our `key` option.
if (!event.metaKey || event.key != key) return
// Prevent the default characters from being inserted.
event.preventDefault()
@@ -94,7 +94,7 @@ Now that we have our plugin, let's remove the hard-coded logic from our app, and
// Initialize our bold-mark-adding plugin.
const boldPlugin = MarkHotkey({
type: 'bold',
code: 66
key: 'b'
})
// Create an array of plugins.
@@ -139,11 +139,11 @@ Let's add _italic_, `code`, ~~strikethrough~~ and underline marks:
```js
// Initialize a plugin for each mark...
const plugins = [
MarkHotkey({ code: 66, type: 'bold' }),
MarkHotkey({ code: 67, type: 'code', isAltKey: true }),
MarkHotkey({ code: 73, type: 'italic' }),
MarkHotkey({ code: 68, type: 'strikethrough' }),
MarkHotkey({ code: 85, type: 'underline' })
MarkHotkey({ key: 'b', type: 'bold' }),
MarkHotkey({ key: '`', type: 'code' }),
MarkHotkey({ key: 'i', type: 'italic' }),
MarkHotkey({ key: '~', type: 'strikethrough' }),
MarkHotkey({ key: 'u', type: 'underline' })
]
class App extends React.Component {
@@ -182,87 +182,6 @@ class App extends React.Component {
And there you have it! We just added a ton of functionality to the editor with very little work. And we can keep all of our mark hotkey logic tested and isolated in a single place, making maintaining the code easier.
Of course... now that it's reusable, we could actually make our `MarkHotkey` plugin a little easier to use. What if instead of a `code` argument it took the text of the `key` itself? That would make the calling code a lot clearer, since key codes are really obtuse.
In fact, unless you have weirdly good keycode knowledge, you probably have no idea what our current hotkeys actually are.
Let's fix that.
Using the `keycode` module in npm makes this dead simple.
First install it:
```
npm install keycode
```
And then we can add it our plugin:
```js
// Import the keycode module.
import keycode from `keycode`
function MarkHotkey(options) {
// Change the options to take a `key`.
const { type, key, isAltKey = false } = options
return {
onKeyDown(event, data, change) {
// Change the comparison to use the key name.
if (!event.metaKey || keycode(event.which) != key || event.altKey != isAltKey) return
event.preventDefault()
change.toggleMark(type)
return true
}
}
}
```
And now we can make our app code much clearer for the next person who reads it:
```js
// Use the much clearer key names instead of key codes!
const plugins = [
MarkHotkey({ key: 'b', type: 'bold' }),
MarkHotkey({ key: 'c', type: 'code', isAltKey: true }),
MarkHotkey({ key: 'i', type: 'italic' }),
MarkHotkey({ key: 'd', type: 'strikethrough' }),
MarkHotkey({ key: 'u', type: 'underline' })
]
class App extends React.Component {
state = {
state: initialState,
schema: {
marks: {
bold: props => <strong>{props.children}</strong>,
code: props => <code>{props.children}</code>,
italic: props => <em>{props.children}</em>,
strikethrough: props => <del>{props.children}</del>,
underline: props => <u>{props.children}</u>,
}
}
}
onChange = ({ state }) => {
this.setState({ state })
}
render() {
return (
<Editor
plugins={plugins}
schema={this.state.schema}
state={this.state.state}
onChange={this.onChange}
/>
)
}
}
```
That's why plugins are awesome. They let you get really expressive while also making your codebase easier to manage. And since Slate is built with plugins as a primary consideration, using them is dead simple!

View File

@@ -116,7 +116,7 @@ class CheckLists extends React.Component {
const { state } = change
if (
data.key == 'enter' &&
e.key == 'Enter' &&
state.startBlock.type == 'check-list-item'
) {
return change
@@ -125,7 +125,7 @@ class CheckLists extends React.Component {
}
if (
data.key == 'backspace' &&
e.key == 'Backspace' &&
state.isCollapsed &&
state.startBlock.type == 'check-list-item' &&
state.selection.startOffset == 0

View File

@@ -174,7 +174,7 @@ class CodeHighlighting extends React.Component {
onKeyDown = (e, data, change) => {
const { state } = change
const { startBlock } = state
if (data.key != 'enter') return
if (e.key != 'Enter') return
if (startBlock.type != 'code') return
if (state.isExpanded) change.delete()
return change.insertText('\n')

View File

@@ -96,40 +96,6 @@ class HugeDocument extends React.Component {
this.setState({ state })
}
/**
* On key down, if it's a formatting command toggle a mark.
*
* @param {Event} e
* @param {Object} data
* @param {Change} change
*/
onKeyDown = (e, data, change) => {
if (!data.isMod) return
let mark
switch (data.key) {
case 'b':
mark = 'bold'
break
case 'i':
mark = 'italic'
break
case 'u':
mark = 'underlined'
break
case '`':
mark = 'code'
break
default:
return
}
e.preventDefault()
change.toggleMark(mark)
return true
}
/**
* Render the editor.
*

View File

@@ -105,10 +105,10 @@ class MarkdownShortcuts extends React.Component {
*/
onKeyDown = (e, data, change) => {
switch (data.key) {
case 'space': return this.onSpace(e, change)
case 'backspace': return this.onBackspace(e, change)
case 'enter': return this.onEnter(e, change)
switch (e.key) {
case ' ': return this.onSpace(e, change)
case 'Backspace': return this.onBackspace(e, change)
case 'Enter': return this.onEnter(e, change)
}
}

View File

@@ -3,14 +3,28 @@ import { Editor } from 'slate-react'
import { State } from 'slate'
import React from 'react'
import isHotkey from 'is-hotkey'
import initialState from './state.json'
/**
* Define the default node type.
*
* @type {String}
*/
const DEFAULT_NODE = 'paragraph'
/**
* Hotkey matchers.
*
* @type {Function}
*/
const isBoldHotkey = isHotkey('mod+b')
const isItalicHotkey = isHotkey('mod+i')
const isUnderlinedHotkey = isHotkey('mod+u')
const isCodeHotkey = isHotkey('mod+`')
/**
* Define a schema.
*
@@ -107,23 +121,17 @@ class RichTextExample extends React.Component {
*/
onKeyDown = (e, data, change) => {
if (!data.isMod) return
let mark
switch (data.key) {
case 'b':
if (isBoldHotkey(e)) {
mark = 'bold'
break
case 'i':
} else if (isItalicHotkey(e)) {
mark = 'italic'
break
case 'u':
} else if (isUnderlinedHotkey(e)) {
mark = 'underlined'
break
case '`':
} else if (isCodeHotkey(e)) {
mark = 'code'
break
default:
} else {
return
}

View File

@@ -54,7 +54,7 @@ class PlainText extends React.Component {
*/
onKeyDown = (e, data, change) => {
if (data.key == 'enter' && data.isShift) {
if (e.key == 'Enter' && e.shiftKey) {
e.preventDefault()
change.insertText('\n')
return true

View File

@@ -3,8 +3,20 @@ import { Editor } from 'slate-react'
import { State } from 'slate'
import React from 'react'
import isHotkey from 'is-hotkey'
import initialState from './state.json'
/**
* Hotkey matchers.
*
* @type {Function}
*/
const isBoldHotkey = isHotkey('mod+b')
const isItalicHotkey = isHotkey('mod+i')
const isUnderlinedHotkey = isHotkey('mod+u')
const isCodeHotkey = isHotkey('mod+`')
/**
* Define a schema.
*
@@ -100,23 +112,17 @@ class SyncingEditor extends React.Component {
*/
onKeyDown = (e, data, change) => {
if (!data.isMod) return
let mark
switch (data.key) {
case 'b':
if (isBoldHotkey(e)) {
mark = 'bold'
break
case 'i':
} else if (isItalicHotkey(e)) {
mark = 'italic'
break
case 'u':
} else if (isUnderlinedHotkey(e)) {
mark = 'underlined'
break
case '`':
} else if (isCodeHotkey(e)) {
mark = 'code'
break
default:
} else {
return
}

View File

@@ -118,10 +118,10 @@ class Tables extends React.Component {
return
}
switch (data.key) {
case 'backspace': return this.onBackspace(e, state)
case 'delete': return this.onDelete(e, state)
case 'enter': return this.onEnter(e, state)
switch (e.key) {
case 'Backspace': return this.onBackspace(e, state)
case 'Delete': return this.onDelete(e, state)
case 'Enter': return this.onEnter(e, state)
}
}

View File

@@ -27,6 +27,7 @@
"gh-pages": "^0.11.0",
"http-server": "^0.9.0",
"immutable": "^3.8.1",
"is-hotkey": "^0.0.1",
"is-image": "^1.0.1",
"is-url": "^1.2.2",
"jest": "^17.0.3",

View File

@@ -572,14 +572,17 @@ class Content extends React.Component {
if (this.props.readOnly) return
if (!this.isInEditor(event.target)) return
const { altKey, ctrlKey, metaKey, shiftKey, which } = event
const key = keycode(which)
const { key, metaKey, ctrlKey } = event
const data = {}
const modKey = IS_MAC ? metaKey : ctrlKey
// COMPAT: add the deprecated keyboard event properties.
addDeprecatedKeyProperties(data, event)
// Keep track of an `isShifting` flag, because it's often used to trigger
// "Paste and Match Style" commands, but isn't available on the event in a
// normal paste event.
if (key == 'shift') {
if (key == 'Shift') {
this.tmp.isShifting = true
}
@@ -588,35 +591,23 @@ class Content extends React.Component {
// selection-moving behavior.
if (
this.tmp.isComposing &&
(key == 'left' || key == 'right' || key == 'up' || key == 'down')
(key == 'ArrowLeft' || key == 'ArrowRight' || key == 'ArrowUp' || key == 'ArrowDown')
) {
event.preventDefault()
return
}
// Add helpful properties for handling hotkeys to the data object.
data.code = which
data.key = key
data.isAlt = altKey
data.isCmd = IS_MAC ? metaKey && !altKey : false
data.isCtrl = ctrlKey && !altKey
data.isLine = IS_MAC ? metaKey : false
data.isMeta = metaKey
data.isMod = IS_MAC ? metaKey && !altKey : ctrlKey && !altKey
data.isModAlt = IS_MAC ? metaKey && altKey : ctrlKey && altKey
data.isShift = shiftKey
data.isWord = IS_MAC ? altKey : ctrlKey
// These key commands have native behavior in contenteditable elements which
// will cause our state to be out of sync, so prevent them.
if (
(key == 'enter') ||
(key == 'backspace') ||
(key == 'delete') ||
(key == 'b' && data.isMod) ||
(key == 'i' && data.isMod) ||
(key == 'y' && data.isMod) ||
(key == 'z' && data.isMod)
(key == 'Enter') ||
(key == 'Backspace') ||
(key == 'Delete') ||
(key == 'b' && modKey) ||
(key == 'i' && modKey) ||
(key == 'y' && modKey) ||
(key == 'z' && modKey) ||
(key == 'Z' && modKey)
) {
event.preventDefault()
}
@@ -632,27 +623,15 @@ class Content extends React.Component {
*/
onKeyUp = (event) => {
const { altKey, ctrlKey, metaKey, shiftKey, which } = event
const key = keycode(which)
const data = {}
if (key == 'shift') {
// COMPAT: add the deprecated keyboard event properties.
addDeprecatedKeyProperties(data, event)
if (event.key == 'Shift') {
this.tmp.isShifting = false
}
// Add helpful properties for handling hotkeys to the data object.
data.code = which
data.key = key
data.isAlt = altKey
data.isCmd = IS_MAC ? metaKey && !altKey : false
data.isCtrl = ctrlKey && !altKey
data.isLine = IS_MAC ? metaKey : false
data.isMeta = metaKey
data.isMod = IS_MAC ? metaKey && !altKey : ctrlKey && !altKey
data.isModAlt = IS_MAC ? metaKey && altKey : ctrlKey && altKey
data.isShift = shiftKey
data.isWord = IS_MAC ? altKey : ctrlKey
debug('onKeyUp', { event, data })
this.props.onKeyUp(event, data)
}
@@ -669,9 +648,16 @@ class Content extends React.Component {
const data = getTransferData(event.clipboardData)
// Attach the `isShift` flag, so that people can use it to trigger "Paste
// and Match Style" logic.
data.isShift = !!this.tmp.isShifting
// COMPAT: Attach the `isShift` flag, so that people can use it to trigger
// "Paste and Match Style" logic.
Object.defineProperty(data, 'isShift', {
enumerable: true,
get() {
logger.deprecate('0.28.0', 'The `data.isShift` property of paste events has been deprecated. If you need this functionality, you\'ll need to keep track of that state with `onKeyDown` and `onKeyUp` events instead')
return !!this.tmp.isShifting
}
})
debug('onPaste', { event, data })
// COMPAT: In IE 11, only plain text can be retrieved from the event's
@@ -897,6 +883,40 @@ class Content extends React.Component {
}
/**
* Add deprecated `data` fields from a key `event`.
*
* @param {Object} data
* @param {Object} event
*/
function addDeprecatedKeyProperties(data, event) {
const { altKey, ctrlKey, metaKey, shiftKey, which } = event
const name = keycode(which)
function define(key, value) {
Object.defineProperty(data, key, {
enumerable: true,
get() {
logger.deprecate('0.28.0', `The \`data.${key}\` property of keyboard events is deprecated, please use the native \`event\` properties instead.`)
return value
}
})
}
define('code', which)
define('key', name)
define('isAlt', altKey)
define('isCmd', IS_MAC ? metaKey && !altKey : false)
define('isCtrl', ctrlKey && !altKey)
define('isLine', IS_MAC ? metaKey : false)
define('isMeta', metaKey)
define('isMod', IS_MAC ? metaKey && !altKey : ctrlKey && !altKey)
define('isModAlt', IS_MAC ? metaKey && altKey : ctrlKey && altKey)
define('isShift', shiftKey)
define('isWord', IS_MAC ? altKey : ctrlKey)
}
/**
* Export.
*

View File

@@ -407,19 +407,20 @@ function Plugin(options = {}) {
function onKeyDown(e, data, change) {
debug('onKeyDown', { data })
switch (data.key) {
case 'enter': return onKeyDownEnter(e, data, change)
case 'backspace': return onKeyDownBackspace(e, data, change)
case 'delete': return onKeyDownDelete(e, data, change)
case 'left': return onKeyDownLeft(e, data, change)
case 'right': return onKeyDownRight(e, data, change)
case 'up': return onKeyDownUp(e, data, change)
case 'down': return onKeyDownDown(e, data, change)
switch (e.key) {
case 'Enter': return onKeyDownEnter(e, data, change)
case 'Backspace': return onKeyDownBackspace(e, data, change)
case 'Delete': return onKeyDownDelete(e, data, change)
case 'ArrowLeft': return onKeyDownLeft(e, data, change)
case 'ArrowRight': return onKeyDownRight(e, data, change)
case 'ArrowUp': return onKeyDownUp(e, data, change)
case 'ArrowDown': return onKeyDownDown(e, data, change)
case 'd': return onKeyDownD(e, data, change)
case 'h': return onKeyDownH(e, data, change)
case 'k': return onKeyDownK(e, data, change)
case 'y': return onKeyDownY(e, data, change)
case 'z': return onKeyDownZ(e, data, change)
case 'z':
case 'Z': return onKeyDownZ(e, data, change)
}
}
@@ -457,9 +458,13 @@ function Plugin(options = {}) {
*/
function onKeyDownBackspace(e, data, change) {
const isWord = IS_MAC ? e.altKey : e.ctrlKey
const isLine = IS_MAC ? e.metaKey : false
let boundary = 'Char'
if (data.isWord) boundary = 'Word'
if (data.isLine) boundary = 'Line'
if (isWord) boundary = 'Word'
if (isLine) boundary = 'Line'
change[`delete${boundary}Backward`]()
}
@@ -472,9 +477,13 @@ function Plugin(options = {}) {
*/
function onKeyDownDelete(e, data, change) {
const isWord = IS_MAC ? e.altKey : e.ctrlKey
const isLine = IS_MAC ? e.metaKey : false
let boundary = 'Char'
if (data.isWord) boundary = 'Word'
if (data.isLine) boundary = 'Line'
if (isWord) boundary = 'Word'
if (isLine) boundary = 'Line'
change[`delete${boundary}Forward`]()
}
@@ -496,8 +505,8 @@ function Plugin(options = {}) {
function onKeyDownLeft(e, data, change) {
const { state } = change
if (data.isCtrl) return
if (data.isAlt) return
if (e.ctrlKey) return
if (e.altKey) return
if (state.isExpanded) return
const { document, startKey, startText } = state
@@ -519,7 +528,7 @@ function Plugin(options = {}) {
const previousInline = document.getClosestInline(previous.key)
if (previousBlock === startBlock && previousInline && !previousInline.isVoid) {
const extendOrMove = data.isShift ? 'extend' : 'move'
const extendOrMove = e.shiftKey ? 'extend' : 'move'
change.collapseToEndOf(previous)[extendOrMove](-1)
return
}
@@ -552,8 +561,8 @@ function Plugin(options = {}) {
function onKeyDownRight(e, data, change) {
const { state } = change
if (data.isCtrl) return
if (data.isAlt) return
if (e.ctrlKey) return
if (e.altKey) return
if (state.isExpanded) return
const { document, startKey, startText } = state
@@ -581,7 +590,7 @@ function Plugin(options = {}) {
const nextInline = document.getClosestInline(next.key)
if (nextBlock == startBlock && nextInline) {
const extendOrMove = data.isShift ? 'extend' : 'move'
const extendOrMove = e.shiftKey ? 'extend' : 'move'
change.collapseToStartOf(next)[extendOrMove](1)
return
}
@@ -604,11 +613,11 @@ function Plugin(options = {}) {
*/
function onKeyDownUp(e, data, change) {
if (!IS_MAC || data.isCtrl || !data.isAlt) return
if (!IS_MAC || e.ctrlKey || !e.altKey) return
const { state } = change
const { selection, document, focusKey, focusBlock } = state
const transform = data.isShift ? 'extendToStartOf' : 'collapseToStartOf'
const transform = e.shiftKey ? 'extendToStartOf' : 'collapseToStartOf'
const block = selection.hasFocusAtStartOf(focusBlock)
? document.getPreviousBlock(focusKey)
: focusBlock
@@ -633,11 +642,11 @@ function Plugin(options = {}) {
*/
function onKeyDownDown(e, data, change) {
if (!IS_MAC || data.isCtrl || !data.isAlt) return
if (!IS_MAC || e.ctrlKey || !e.altKey) return
const { state } = change
const { selection, document, focusKey, focusBlock } = state
const transform = data.isShift ? 'extendToEndOf' : 'collapseToEndOf'
const transform = e.shiftKey ? 'extendToEndOf' : 'collapseToEndOf'
const block = selection.hasFocusAtEndOf(focusBlock)
? document.getNextBlock(focusKey)
: focusBlock
@@ -658,7 +667,7 @@ function Plugin(options = {}) {
*/
function onKeyDownD(e, data, change) {
if (!IS_MAC || !data.isCtrl) return
if (!IS_MAC || !e.ctrlKey || e.altKey) return
e.preventDefault()
change.deleteCharForward()
}
@@ -672,7 +681,7 @@ function Plugin(options = {}) {
*/
function onKeyDownH(e, data, change) {
if (!IS_MAC || !data.isCtrl) return
if (!IS_MAC || !e.ctrlKey || e.altKey) return
e.preventDefault()
change.deleteCharBackward()
}
@@ -686,7 +695,7 @@ function Plugin(options = {}) {
*/
function onKeyDownK(e, data, change) {
if (!IS_MAC || !data.isCtrl) return
if (!IS_MAC || !e.ctrlKey || e.altKey) return
e.preventDefault()
change.deleteLineForward()
}
@@ -700,7 +709,8 @@ function Plugin(options = {}) {
*/
function onKeyDownY(e, data, change) {
if (!data.isMod) return
const modKey = IS_MAC ? e.metaKey : e.ctrlKey
if (!modKey) return
change.redo()
}
@@ -713,8 +723,9 @@ function Plugin(options = {}) {
*/
function onKeyDownZ(e, data, change) {
if (!data.isMod) return
change[data.isShift ? 'redo' : 'undo']()
const modKey = IS_MAC ? e.metaKey : e.ctrlKey
if (!modKey) return
change[e.shiftKey ? 'redo' : 'undo']()
}
/**

View File

@@ -3,7 +3,7 @@
import h from '../../../helpers/h'
export default function (simulator) {
simulator.keyDown(null, { key: 'enter' })
simulator.keyDown({ key: 'Enter' })
}
export const input = (

View File

@@ -3360,6 +3360,10 @@ is-glob@^3.1.0:
dependencies:
is-extglob "^2.1.0"
is-hotkey@^0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/is-hotkey/-/is-hotkey-0.0.1.tgz#d8d817209b34292551a85357e65cdbfcfa763443"
is-image@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-image/-/is-image-1.0.1.tgz#6fd51a752a1a111506d060d952118b0b989b426e"