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

Update docs (#1893)

This commit is contained in:
David Chang
2018-06-12 10:42:09 -07:00
committed by Ian Storm Taylor
parent b26535fd94
commit bcf41a96b4
8 changed files with 42 additions and 42 deletions

View File

@@ -12,7 +12,7 @@ Because it mirrors the DOM, Slate's data model features a [`Document`](../refere
## Immutable Objects
Slate's data model is built out of [`Immutable.js`](https://facebook.github.io/immutable-js/) objects. This allows us to make rendering much more performant, and it ensures that we don't end up with hard to track down bugs.
Slate's data model is built out of [`Immutable.js`](https://facebook.github.io/immutable-js/) objects. This allows us to make rendering much more performant, and it ensures that we don't end up with hard to track down bugs due to accidentally modifying objects in-place.
Specifically, Slate's models are [`Immutable.Record`](https://facebook.github.io/immutable-js/docs/#/Record) objects, which makes them very similar to Javascript objects for retrieiving values:
@@ -25,13 +25,13 @@ block.type // "paragraph"
But for updating values, you'll need to use the [`Immutable.Record` API](https://facebook.github.io/immutable-js/docs/#/Record/set).
Collections of Slate objects are represented as immutable `Lists`, `Sets`, `Stacks`, etc. Which means we get nice support for expressive methods like `filter`, `includes`, `take`, `skip`, `rest`, `last`, etc.
Collections of Slate objects are represented as immutable `Lists`, `Sets`, `Stacks`, etc, which means we get nice support for expressive methods like `filter`, `includes`, `take`, `skip`, `rest` and `last`.
If you haven't used Immutable.js before, there is definitely a learning curve. Before you dive into Slate, you should check out the [Immutable.js docs](https://facebook.github.io/immutable-js/docs/#/). Once you get the hang of it, it won't slow you down at all, but it will take a few days to get used to, and you might write things a little "un-performantly" to start.
If you haven't used Immutable.js before, there is definitely a learning curve. Before you dive into Slate, you should check out the [Immutable.js docs](https://facebook.github.io/immutable-js/docs/#/). Once you get the hang of it, it won't slow you down at all, but it will take a few days to get used to, and you might write things suboptimally at first.
## The "Value"
The top-level object in Slate—the object encapsulates the entire value of an Slate editor—is called a [`Value`](../reference/slate/value.md).
The top-level object in Slate—the object encapsulating the entire value of an Slate editor—is called a [`Value`](../reference/slate/value.md).
It is made up of a document filled with content, and a selection representing the user's current cursor selection. It also has a history, to keep track of changes, and a few other more advanced properties like `decorations` and `data`.
@@ -39,9 +39,9 @@ It is made up of a document filled with content, and a selection representing th
## Documents and Nodes
Slate documents are nested and recursive. This means that a document has block nodes, and those block nodes can have child block nodes—all the way down. This lets you model more complex nested behaviors like tables, or figures with captions.
Slate documents are nested and recursive. This means that a document has block nodes, and those block nodes can have child block nodes—all the way down. This lets you model more complex nested behaviors like tables and figures with captions.
Unlike the DOM though, Slate enforces a few more restrictions on its documents, to reduce the complexity involved in manipulating them, and to prevent "impossible" situations from arising. These restrictions are:
Unlike the DOM though, Slate enforces a few more restrictions on its documents. This reduces the complexity involved in manipulating them and prevents "impossible" situations from arising. These restrictions are:
* **Documents can only contain block nodes as direct children.** This restriction mirrors how rich-text editors work, with the top-most elements being blocks that can be split when pressing <kbd>enter</kbd>.
@@ -53,13 +53,13 @@ Unlike the DOM though, Slate enforces a few more restrictions on its documents,
* **Text nodes can't be adjacent to other text nodes.** Any two adjacent text nodes will automatically be merged into one. This prevents ambiguous cases where a cursor could be at the end of one text node or at the start of the next. However, you can have an inline node surrounded by two texts.
* **Blocks and inlines must always contain at least one text node.** This is to ensure that the user's cursor can always "enter" the nodes, and to make sure that ranges can be created referencing them.
* **Blocks and inlines must always contain at least one text node.** This is to ensure that the user's cursor can always "enter" the nodes and to make sure that ranges can be created referencing them.
Slate enforces all of these restrictions for you automatically. Any time you [perform changes](./changes.md) to the document, Slate will check if the document is invalid, and if so it will return it to a "normalized" value.
Slate enforces all of these restrictions for you automatically. Any time you [perform changes](./changes.md) to the document, Slate will check if the document is invalid, and if so, it will return it to a "normalized" value.
> 🙃 Fun fact: normalizing is actually based on the DOM's [`Node.normalize()`](https://developer.mozilla.org/en-US/docs/Web/API/Node/normalize)!
In addition to documents, blocks and inlines, Slate introduces one other type of markup that the DOM doesn't have natively: the [`Mark`](../reference/slate/mark.md).
In addition to documents, blocks and inlines, Slate introduces one other type of markup that the DOM doesn't have natively, the [`Mark`](../reference/slate/mark.md).
## Marks
@@ -92,7 +92,7 @@ That all sounds pretty complex, but you don't have to think about it much, as lo
## Ranges and "The Selection"
Just like in the DOM, you can reference a part of the document using a `Range`. And there's one special range that Slate keeps track of called the "selection" that refers to the user's current cursor selection.
Just like in the DOM, you can reference a part of the document using a `Range`. And there's one special range that Slate keeps track of that refers to the user's current cursor selection, called the "selection".
Ranges are defined by an "anchor" and "focus" point. The anchor is where the range starts, and the focus is where it ends. And each point is a combination of a "key" referencing a specific node, and an "offset". This ends up looking like this:
@@ -108,7 +108,7 @@ const range = Range.create({
The more readable `node-a` name is just pseudocode, because Slate uses auto-incrementing numerical strings by default—`'1', '2', '3', ...` But the important part is that every node has a unique `key` property, and a range references nodes by their keys.
The terms "anchor" and "focus" are borrowed from the DOM, where they mean the same thing. The anchor is where a range starts, and the focus is where it ends. However, be careful because the anchor point isn't always _before_ the focus point in the document. Just like in the DOM, it depends on whether the range is backwards or forwards.
The terms "anchor" and "focus" are borrowed from the DOM, where they mean the same thing. The anchor point isn't always _before_ the focus point in the document. Just like in the DOM, it depends on whether the range is backwards or forwards.
Here's how MDN explains it:

View File

@@ -10,7 +10,7 @@ To that end, Slate provides a `Schema` model, which allows you to easily define
## Basic Schemas
Slate schemas are defined as Javascript objects, with properties that describe the document, block nodes, and inlines nodes in your editor. Here's a simple schema:
Slate schemas are defined as Javascript objects, with properties that describe the document, block nodes, and inline nodes in your editor. Here's a simple schema:
```js
const schema = {
@@ -47,7 +47,7 @@ By default, Slate will normalize any invalid states to ensure that the document
For example, with the above schema, if a block that isn't a `paragraph` or an `image` is discovered in the document, Slate will simply remove it.
But you might want to preserve the node, and instead just convert it to a `paragraph`, this way you aren't losing whatever the node's content was. Slate doesn't know those kinds of specifics about your data model, and trying to express all of these types of preferences in a declarative schema is a huge recipe for complexity.
But you might want to preserve the node, and instead just convert it to a `paragraph`-this way you aren't losing whatever the node's content was. Slate doesn't know those kinds of specifics about your data model, and trying to express all of these types of preferences in a declarative schema is a huge recipe for complexity.
Instead, Slate lets you define your own custom normalization logic.
@@ -69,7 +69,7 @@ const schema = {
That's an example of defining your own custom `normalize` option for the document validation. If the invalid reason is `child_type_invalid`, it will set the child to be a `paragraph`.
When Slate discovers an invalid child, it will first check to see if your custom normalizer handles that case, and if it does Slate won't do any of its default behavior. That way you can opt-in to customizing the normalization logic for specific cases, without having to re-implement all of the defaults yourself.
When Slate discovers an invalid child, it will first check to see if your custom normalizer handles that case; if your normalizer handles it, then Slate won't run any of its default behavior. This way, you can opt-in to customizing the normalization logic for specific cases without having to re-implement all of the defaults yourself.
This gives you the best of both worlds. You can write simple, terse, declarative validation rules that can be highly optimized. But you can still define fine-grained, imperative normalization logic for when invalid states occur.
@@ -103,11 +103,11 @@ This validation defines a very specific (honestly, useless) behavior, where if a
When you need this level of specificity, using the `validateNode` property of the editor or plugins is handy.
However, only use it when you absolutely have to. And when you do, you need to be aware of its performance. `validateNode` will be called **every time the node changes**, so it should be as performant as possible. That's why the example above returns early, so that the smallest amount of work is done as possible each time it is called.
However, only use it when you absolutely have to. And when you do, make sure to optimize the function's performance. `validateNode` will be called **every time the node changes**, so it should be as performant as possible. That's why the example above returns early, so that the smallest amount of work is done each time it is called.
## Multi-step Normalizations
Some normalizations will require multiple `change` function calls in order to complete. But after calling the first change function, the resulting document will be normalized, changing it out from under you. This can cause unintended behaviors.
Some normalizations will require multiple `change` function calls in order to complete. But after calling the first change function, the resulting document will be normalized, changing the document out from underneath you. This can cause unintended behaviors.
Consider the following validation function that merges adjacent text nodes together.

View File

@@ -67,4 +67,4 @@ function onBeforeInput(event, change, editor) {
}
```
Notice that is calls `event.preventDefault()` to prevent the default browser behavior, and it returns `false` to prevent the editor from continuing to resolve its plugins stack.
Notice that it calls `event.preventDefault()` to prevent the default browser behavior, and it returns `false` to prevent the editor from continuing to resolve its plugins stack.

View File

@@ -29,19 +29,19 @@ The top-level React component that renders the Slate editor itself.
`Boolean`
Whether the editor should attempt to autocorrect spellcheck errors.
Whether or not the editor should attempt to autocorrect spellcheck errors.
### `autoFocus`
`Boolean`
An optional attribute that, when set to true, attempts to give the content editable element focus when it's loaded onto the page.
Whether or not the editor should attempt to give the contenteditable element focus when it's loaded onto the page.
### `className`
`String`
An optional class name to apply to the content editable element.
An optional class name to apply to the contenteditable element.
### `onChange`
@@ -77,13 +77,13 @@ ARIA property to define the role of the editor, it defaults to `textbox` when ed
`Boolean`
Whether spellcheck is turned on for the editor.
Whether or not spellcheck is turned on for the editor.
### `style`
`Object`
An optional dictionary of styles to apply to the content editable element.
An optional dictionary of styles to apply to the contenteditable element.
### `tabIndex`
@@ -170,7 +170,7 @@ Programmatically blur the editor.
`change(fn) => Void`
`change(fn, ...args) => Void`
Programmatically invoke a change `fn` on the editor. The function will be invokved with a new `change` object representing the editor's current value.
Programmatically invoke a change `fn` on the editor. The function will be invoked with a new `change` object representing the editor's current value.
If extra `...args` are passed in, the change `fn` will be invoked with `(change, ...args)`, so you can use this as a shorthand for performing single-function changes.

View File

@@ -1,6 +1,6 @@
# `Schema`
Every Slate editor has a "schema" associated with it, which contains information about the structure of its content. For the most basic cases, you'll just rely on Slate's default core schema. But for advanced use cases you can enforce rules about what the content of a Slate document can contain.
Every Slate editor has a "schema" associated with it, which contains information about the structure of its content. For the most basic cases, you'll just rely on Slate's default core schema. But for advanced use cases, you can enforce rules about what the content of a Slate document can contain.
## Properties
@@ -12,7 +12,7 @@ Every Slate editor has a "schema" associated with it, which contains information
}
```
The top-level properties of a schema all give you a way to define validation "rules" that the schema enforces.
The top-level properties of a schema give you a way to define validation "rules" that the schema enforces.
### `document`
@@ -80,7 +80,7 @@ A dictionary of inlines by type, each with its own set of validation rules.
}
```
Slate schemas are built up of a set of validation rules. Each of the properties will validate certain pieces of the document based on the properties it defines.
Slate schemas are built using a set of validation rules. Each of the properties will validate certain pieces of the document based on the properties it defines.
### `data`
@@ -159,7 +159,7 @@ Will validate a node's children. The `nodes` definitions can declare the `object
}
```
Will validate a node's marks. The `marks` definitions can declare a list of marks type to be allowed. If declared, any marks that are not in the list will be removed.
Will validate a node's marks. The `marks` definitions can declare a list of mark types to be allowed. If declared, any marks that are not in the list will be removed.
### `normalize`
@@ -180,9 +180,9 @@ Will validate a node's marks. The `marks` definitions can declare a list of mark
}
```
A function that can be provided to override the default behavior in the case of a rule being invalid. By default Slate will do what it can, but since it doesn't know much about your schema, it will often remove invalid nodes. If you want to override this behavior, and "fix" the node instead of removing it, pass a custom `normalize` function.
A function that can be provided to override the default behavior in the case of a rule being invalid. By default, Slate will do what it can, but since it doesn't know much about your schema, it will often remove invalid nodes. If you want to override this behavior and "fix" the node instead of removing it, pass a custom `normalize` function.
For more information on the arguments passed to `normalize`, see the [Violations](#violations) reference.
For more information on the arguments passed to `normalize`, see the [Violations](#violations) section.
### `parent`

View File

@@ -35,7 +35,7 @@ Now... we need to add the [`Html`](../reference/serializers/html.md) serializer.
* A `quote` block for quotes...
* And `bold`, `italic` and `underline` formatting.
By default, the `Html` serializer, knows nothing about our schema just like Slate itself. To fix this, we need to pass it a set of `rules`. Each rule defines how to serialize and deserialize a Slate object.
By default, the `Html` serializer knows nothing about our schema, just like Slate itself. To fix this, we need to pass it a set of `rules`. Each rule defines how to serialize and deserialize a Slate object.
To start, let's create a new rule with a `deserialize` function for paragraph blocks.
@@ -287,11 +287,11 @@ class App extends React.Component {
const { mark, attributes } = props
switch (mark.type) {
case 'bold':
return <strong {...{ attributes }}>{props.children}</strong>
return <strong {...attributes}>{props.children}</strong>
case 'italic':
return <em {...{ attributes }}>{props.children}</em>
return <em {...attributes}>{props.children}</em>
case 'underline':
return <u {...{ attributes }}>{props.children}</u>
return <u {...attributes}>{props.children}</u>
}
}
}

View File

@@ -147,7 +147,7 @@ class App extends React.Component {
Now you should be able to save changes across refreshes!
However, if you inspect the change handler, you'll notice that it's actually saving the Local Storage value on _every_ change to the editor, even when only the selection changes! This is because `onChange` is called for _every_ change. For Local Storage this doesn't really matter, but if you're saving things to a database via HTTP request this would result in a lot of unnecessary requests. You can fix this by checking against the previous `document` value.
However, if you inspect the change handler, you'll notice that it's actually saving the Local Storage value on _every_ change to the editor, even when only the selection changes! This is because `onChange` is called for _every_ change. For Local Storage, this doesn't really matter, but if you're saving things to a database via HTTP request, this would result in a lot of unnecessary requests. You can fix this by checking against the previous `document` value.
```js
const existingValue = JSON.parse(localStorage.getItem('content'))

View File

@@ -4,11 +4,11 @@
# Using Plugins
Up to now, everything we've learned has been about how to write one-off logic for your specific Slate editor. But one of the most beautiful things about Slate is actually its plugin system, and how it lets you write less one-off code.
Up until now, everything we've learned has been about how to write one-off logic for your specific Slate editor. But one of the most beautiful things about Slate is actually its plugin system and how it lets you write less one-off code.
In the previous guide, we actually wrote some pretty useful code for adding **bold** formatting to ranges of text when a key is pressed. But most of that code wasn't really specific to **bold** text; it could just as easily have applied to _italic_ text or `code` text if we switched a few variables.
So let's break that logic out into it's a reusable plugin that can toggle _any_ mark on _any_ key press.
So let's break that logic out into a reusable plugin that can toggle _any_ mark on _any_ key press.
Starting with our app from earlier:
@@ -43,13 +43,13 @@ class App extends React.Component {
renderMark = props => {
switch (props.mark.type) {
case 'bold':
return <strong {...{props.attributes}}>{props.children}</strong>
return <strong {...props.attributes}>{props.children}</strong>
}
}
}
```
Let's write a new function, that takes a set of options: the mark `type` to toggle and the `key` 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) {
@@ -60,9 +60,9 @@ function MarkHotkey(options) {
Okay, that was easy. But it doesn't do anything.
To fix that, we need our plugin function to return a "plugin object" that Slate recognizes. Slate's plugin objects are just plain objects that have properties that map to the same handler on the `Editor`.
To fix that, we need our plugin function to return a "plugin object" that Slate recognizes. Slate's plugin objects are just plain JavaScript objects whose properties map to the same handlers on the `Editor`.
In this case our plugin object will have one property: a `onKeyDown` handler, with its logic copied right from our current app's code:
In this case, our plugin object will have one property, an `onKeyDown` handler, with its logic copied right from our current app's code:
```js
function MarkHotkey(options) {
@@ -87,7 +87,7 @@ function MarkHotkey(options) {
Boom! Now we're getting somewhere. That code is reusable for any type of mark.
Now that we have our plugin, let's remove the hard-coded logic from our app, and replace it with our brand new `MarkHotkey` plugin instead, passing in the same options that will keep our **bold** functionality intact:
Now that we have our plugin, let's remove the hard-coded logic from our app and replace it with our brand new `MarkHotkey` plugin instead, passing in the same options that will keep our **bold** functionality intact:
```js
// Initialize our bold-mark-adding plugin.
@@ -181,7 +181,7 @@ 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.
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 the code easier to maintain.
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!