#### Is this adding or improving a _feature_ or fixing a _bug_?
Improvement / debt.
#### What's the new behavior?
This pull request removes the `Change` object as we know it, and folds all of its behaviors into the new `Editor` controller instead, simplifying a lot of the confusion around what is a "change vs. editor" and when to use which. It makes the standard API a **lot** nicer to use I think.
---
###### NEW
**The `editor.command` and `editor.query` methods can take functions.** Previously they only accepted a `type` string and would look up the command or query by type. Now, they also accept a custom function. This is helpful for plugin authors, who want to accept a "command option", since it gives users more flexibility to write one-off commands or queries. For example a plugin could be passed either:
```js
Hotkey({
hotkey: 'cmd+b',
command: 'addBoldMark',
})
```
Or a custom command function:
```js
Hotkey({
hotkey: 'cmd+b',
command: editor => editor.addBoldMark().moveToEnd()
})
```
###### BREAKING
**The `Change` object has been removed.** The `Change` object as we know it previously has been removed, and all of its behaviors have been folded into the `Editor` controller. This includes the top-level commands and queries methods, as well as methods like `applyOperation` and `normalize`. _All places that used to receive `change` now receive `editor`, which is API equivalent._
**Changes are now flushed to `onChange` asynchronously.** Previously this was done synchronously, which resulted in some strange race conditions in React environments. Now they will always be flushed asynchronously, just like `setState`.
**The `render*` and `decorate*` middleware signatures have changed!** Previously the `render*` and `decorate*` middleware was passed `(props, next)`. However now, for consistency with the other middleware they are all passed `(props, editor, next)`. This way, all middleware always receive `editor` and `next` as their final two arguments.
**The `normalize*` and `validate*` middleware signatures have changed!** Previously the `normalize*` and `validate*` middleware was passed `(node, next)`. However now, for consistency with the other middleware they are all passed `(node, editor, next)`. This way, all middleware always receive `editor` and `next` as their final two arguments.
**The `editor.event` method has been removed.** Previously this is what you'd use when writing tests to simulate events being fired—which were slightly different to other running other middleware. With the simplification to the editor and to the newly-consistent middleware signatures, you can now use `editor.run` directly to simulate events:
```js
editor.run('onKeyDown', { key: 'Tab', ... })
```
###### DEPRECATED
**The `editor.change` method is deprecated.** With the removal of the `Change` object, there's no need anymore to create the small closures with `editor.change()`. Instead you can directly invoke commands on the editor in series, and all of the changes will be emitted asynchronously on the next tick.
```js
editor
.insertText('word')
.moveFocusForward(10)
.addMark('bold')
```
**The `applyOperations` method is deprecated.** Instead you can loop a set of operations and apply each one using `applyOperation`. This is to reduce the number of methods exposed on the `Editor` to keep it simpler.
**The `change.call` method is deprecated.** Previously this was used to call a one-off function as a change method. Now this behavior is equivalent to calling `editor.command(fn)` instead.
---
Fixes: https://github.com/ianstormtaylor/slate/issues/2334
Fixes: https://github.com/ianstormtaylor/slate/issues/2282
* Add failing deleteAtRange test
* Fix invalid move node path increment (fixes#2291)
* Add another three block delete all test without any void nodes
* Test the correct variables in transform path (move_node)
#### Is this adding or improving a _feature_ or fixing a _bug_?
Fixing a bug. This is a proposed solution for https://github.com/ianstormtaylor/slate/issues/2064 (which also aims to maintain the existing _single nested block_ behavior added in https://github.com/ianstormtaylor/slate/pull/1366).
#### What's the new behavior?
Today, we always insert all nodes of the fragment at the range.
After this change, if the fragment is wrapped by/nested in blocks, and the nesting pattern already exists at the range, we meld the fragment contents into the document’s existing nesting pattern as much as possible.
Put another way, we can skip adding the fragment’s wrapping nodes if equivalent nodes already wrap the range.
Here’s a quick sketch that may better demonstrate the intention:
![image](https://user-images.githubusercontent.com/1694410/47054250-d6862480-d17e-11e8-89b8-337d7569389e.png)
Here, both the document and fragment wrap their content in two paragraphs. Therefore, we can add the fragment contents within the existing pair of nested paragraphs.
#### How does this change work?
A new function is added, `findInsertionNode`. Given a `fragment`, `document`, and `startKey`, it returns a node from the fragment to be inserted into the document. By default, the node returned will be the `fragment`, but if a common nesting pattern is detected, a sub-node of the fragment will be returned.
The detection algorithm is as follows:
1. Ensure the fragment has a single child node, call it `fragmentInner`
2. Find the furthest document ancestor of the `startKey` matching `fragmentInner.type`. Call this `documentInner`
3. Drill into both `documentInner` and `fragmentInner` as long as each has a single child node and their types match. The stopping point for the fragment is the sub-node to insert into the document.
`Commands.insertFragmentAtRange` remains mostly unchanged. One important modification is that the _single nested block_ (again, see https://github.com/ianstormtaylor/slate/pull/1366) only happens if the found insertion node is the fragment. For anything more inner, we meld.
#### Have you checked that...?
* [x] The new code matches the existing patterns and styles.
* [x] The tests pass with `yarn test`.
* [x] The linter passes with `yarn lint`. (Fix errors with `yarn prettier`.)
* [x] The relevant examples still work. (Run examples with `yarn watch`.)
#### Does this fix any issues or need any specific reviewers?
Fixes: https://github.com/ianstormtaylor/slate/issues/2064
Previously, `start-inline` and `end-inline` included the cursor at the end of an inline, i.e.
```js
<paragraph>
<link>example<cursor /></link>
</paragraph>
```
Using Slate in a browser, it doesn’t seem possible to me to actually achieve this state: i.e. whenever the cursor is on either side of an inline such as a link, typing will not add text to that inline. (This is consistent with other editors, for example Google Docs).
Now, these tests are updated to have a cursor just outside the inline. This leads to more sensible outputs.
(Finally, I removed a TODO comment indicating that `middle-inline-fragment-inline`’s cursor output was incorrect. I believe this is a sensible expectation, which matches behavior in editors including Google Docs.)
Fixes https://github.com/ianstormtaylor/slate/issues/1754
https://github.com/ianstormtaylor/slate/issues/1879
When composition starts and the current selection is not collapsed, the
second composition key-down would drop the text wrapping <spans> which
resulted on crash in content.updateSelection after composition ends
(because it cannot find <span> nodes in DOM). This is a workaround that
erases selection as soon as composition starts and preventing <spans>
to be dropped.
* Fix bolded text in input-tester initial value
* Fix crash on Input Tester example with certain input events
If an Input event with inputType "insertReplacementText" is received, the example crashes because "event.dataTransfer.get is not a function"
The correct API is `getData()`, not `get()`.
Ref: https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/getData
* Revert "Fix bolded text in input-tester initial value"
This reverts commit 82e1213be39a9f19c837ff3d28c4c025035d595b.
* Revert "Revert "Fix bolded text in input-tester initial value""
This reverts commit b5a0a2440f388f741222574974cf5fd2ff454a91.
#### Is this adding or improving a _feature_ or fixing a _bug_?
Bug fix - Very minor change
#### What's the new behavior?
`deleteWordBackward` at line ending behaves the same as `deleteCharForward`
#### How does this change work?
If `TextUtils.getWordOffsetForward(text, o)` returns 0, instead we substitute in `1` to delete the line break and join the blocks. The relevant test for this change (`join-blocks`) is also added.
#### Have you checked that...?
<!--
Please run through this checklist for your pull request:
-->
* [x] The new code matches the existing patterns and styles.
* [x] The tests pass with `yarn test`.
* [x] The linter passes with `yarn lint`. (Fix errors with `yarn prettier`.)
* [x] The relevant examples still work. (Run examples with `yarn watch`.)
#### Does this fix any issues or need any specific reviewers?
Fixes: #2258
Reviewers: @ianstormtaylor
#### Is this adding or improving a _feature_ or fixing a _bug_?
_bug_
#### What's the new behavior?
Fix behavior for <kbd>shift + left</kbd> and <kbd>shift + right</kbd>. Now they will correctly move forward / backward.
#### How does this change work?
turns out that the hotkey `'left'` would also pick up with a modifier key `'shift+left'` so checking for `Hotkeys.isExtendForward()` needs to come before `Hotkeys.isMoveForward()` and it needs to short circuit with `return true`. Likewise for backward.
#### Have you checked that...?
<!--
Please run through this checklist for your pull request:
-->
* [x] The new code matches the existing patterns and styles.
* [x] The tests pass with `yarn test`.
* [x] The linter passes with `yarn lint`. (Fix errors with `yarn prettier`.)
* [x] The relevant examples still work. (Run examples with `yarn watch`.)
#### Does this fix any issues or need any specific reviewers?
Fixes: #2307
Reviewers: @ianstormtaylor
* fix: don't check for adjacent void with modified move
This was causing a problem where when the current text was followed by a void node using a modifier key to move forward would force the selection to creep forward a character at a time.
With this change, now the modifier will move as expected, but will jump over void nodes. This is not ideal, but seems like a behavior that will be slightly better than the current one.
* fix: modified key movement.
Use TextUtils.getWordOffsetForward and TextUtils.getWordOffsetBackward to move around by words.
The idea now is that if you move forward or backward, it is completely controlled by slate instead of trying to rely on a combination of browser behavior and slate trying to stop the browser from doing something wrong. This makes things quite a bit more intuitive in the implementation, and gives us a bit more control.
* tests: a whole bunch of selection movement tests.
* tests: more movement tests.
* feat: add a basic mention implementation example
Just a simple example to get people started when trying to implement their own mentions implementation.
* feat(MentionsExample): use a floating suggestions menu.
* fix(MentionsExample): update to slate 0.42
* Rename compare function in path-utils to compareOfSameSize
To make way for a new function that makes a full comparison
* Add compare function to path-utils that handles paths of different sizes
* Add function isAfterRange to Point
* Add function isBeforeRange to Point
* Add function isAtStartOfRange to Point
* Add function isAtEndOfRange to Point
* Add function isInRange to Point
* Add range comparison methods to the documentation of the Point model
* Remove `compareOfSameSize` in `path-utils.js`
Using `compare` instead
* Add `Point.isBeforePoint`
* Add `Point.isAfterPoint`
* Use own methods internally for range comparisons in `Point`
* Return null if paths don't finally match in `compare` method of `path-utils`
To convey that it is not a normal scenario
* Add first test for `Point` model (testing `isAfterPoint`)
* Add tests for `Point.isAfterPoint`
* Add tests for `Point.isBeforePoint`
* Add tests for `Point.isAfterRange`
* Add tests for `Point.isBeforeRange`
* Add tests for `Point.isAtEndOfRange`
* Add tests for `Point.isAtStartOfRange`
* Add tests for `Point.isInRange`
I’m hoping to start making a few contributions myself and was checking this guide out, but noticed that the `✓ easy one` label hasn’t been used in a while and has no open issues.
Instead, we now recommend the `♥ help please` label as a source of issues to fix for potential contributors.