1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-25 00:06:30 +02:00

Rename "state" to "value" everywhere (#1313)

* rename state to value in slate core, as deprecation

* rename all references to state to value in slate core

* migrate slate-base64-serializer

* migrate slate-html-serializer

* migrate slate-hyperscript

* migrate slate-plain-serializer

* migrate slate-prop-types

* migrate slate-simulator

* fix change.setState compat

* deprecate references to state in slate-react

* remove all references to state in slate-react

* remove `value` and `schema` from props to all components

* fix default renderPlaceholder

* fix tests

* update examples

* update walkthroughs

* update guides

* update reference
This commit is contained in:
Ian Storm Taylor
2017-10-27 13:39:06 -07:00
committed by GitHub
parent 44addc8140
commit adb2678732
576 changed files with 3672 additions and 3718 deletions

View File

@@ -1,49 +0,0 @@
This directory contains the React components that Slate renders. Here's what they all do:
- [Content](#content)
- [Editor](#editor)
- [Leaf](#leaf)
- [Placeholder](#placeholder)
- [Text](#text)
- [Void](#void)
#### Content
`Content` is rendered by the [`Editor`](#editor). Its goal is to encapsulate all of the `contenteditable` logic, so that the [`Editor`](#editor) doesn't have to be aware of it.
`Content` handles things attaching event listeners to the DOM and triggering updates based on events. However, it does not have any awareness of "plugins" as a concept, bubbling all of that logic up to the [`Editor`](#editor) itself.
You'll notice there are **no** `Block` or `Inline` components. That's because those rendering components are provided by the user, and rendered directly by the `Content` component. You can find the default renderers in the [`Core`](../plugins/core.js) plugin's logic.
#### Editor
The `Editor` is the highest-level component that you render from inside your application. Its goal is to present a very clean API for the user, and to encapsulate all of the plugin-level logic.
Many of the properties passed into the editor are combined to create a plugin of its own, that is given the highest priority. This makes overriding core logic super simple, without having to write a separate plugin.
#### Leaf
The `Leaf` component is the lowest-level component in the React tree. Its goal is to encapsulate the logic that works at the lowest level, on the actual strings of text in the DOM.
One `Leaf` component is rendered for each range of text with a unique set of [`Marks`](../models#mark). It handles both applying the mark styles to the text, and translating the current [`Selection`](../models#selection) into a real DOM selection, since it knows about the string offsets.
#### Placeholder
A `Placeholder` component is just a convenience for rendering placeholders on top of empty nodes. It's used in the core plugin's default block renderer, but is also exposed to provide the convenient API for custom blocks as well.
#### Text
A `Text` component is rendered for each [`Text`](../models#text) model in the document tree. This component handles grouping the characters of the text node into leaves that have the same set of [`Marks`](../models#mark), and then delegates rendering each leaf to...
#### Void
The `Void` component is a wrapper that gets rendered around [`Block`](../models#block) and [`Inline`](../models#inline) nodes that have `isVoid: true`. Its goal is to encapsule the logic needed to ensure that void nodes function as expected.
To achieve this, `Void` renders a few extra elements that are required to keep selections and keyboard shortcuts on void nodes functioning like you'd expect them two. It also ensures that everything inside the void node is not editable, so that it doesn't get the editor into an unknown state.

View File

@@ -1,7 +1,6 @@
import Debug from 'debug'
import React from 'react'
import SlateTypes from 'slate-prop-types'
import Types from 'prop-types'
import getWindow from 'get-window'
import logger from 'slate-dev-logger'
@@ -43,9 +42,7 @@ class Content extends React.Component {
editor: Types.object.isRequired,
readOnly: Types.bool.isRequired,
role: Types.string,
schema: SlateTypes.schema.isRequired,
spellCheck: Types.bool.isRequired,
state: SlateTypes.state.isRequired,
style: Types.object,
tabIndex: Types.number,
tagName: Types.string,
@@ -124,8 +121,9 @@ class Content extends React.Component {
*/
updateSelection = () => {
const { state } = this.props
const { selection } = state
const { editor } = this.props
const { value } = editor
const { selection } = value
const window = getWindow(this.element)
const native = window.getSelection()
const { rangeCount } = native
@@ -246,11 +244,12 @@ class Content extends React.Component {
// already up to date, but we do want to update the native selection again
// to make sure it is in sync. (2017/10/16)
if (handler == 'onSelect') {
const { state } = this.props
const { selection } = state
const { editor } = this.props
const { value } = editor
const { selection } = value
const window = getWindow(event.target)
const native = window.getSelection()
const range = findRange(native, state)
const range = findRange(native, value)
if (range && range.equals(selection)) {
this.updateSelection()
@@ -323,16 +322,17 @@ class Content extends React.Component {
event.preventDefault()
const { editor, state } = this.props
const { selection } = state
const range = findRange(targetRange, state)
const { editor } = this.props
const { value } = editor
const { selection } = value
const range = findRange(targetRange, value)
editor.change((change) => {
change.insertTextAtRange(range, text, selection.marks)
// If the text was successfully inserted, and the selection had marks on it,
// unset the selection's marks.
if (selection.marks && state.document != change.state.document) {
if (selection.marks && value.document != change.value.document) {
change.select({ marks: null })
}
})
@@ -346,9 +346,10 @@ class Content extends React.Component {
render() {
const { props } = this
const { className, readOnly, state, tabIndex, role, tagName } = props
const { className, readOnly, editor, tabIndex, role, tagName } = props
const { value } = editor
const Container = tagName
const { document, selection } = state
const { document, selection } = value
const indexes = document.getSelectionIndexes(selection, selection.isFocused)
const children = document.nodes.toArray().map((child, i) => {
const isSelected = !!indexes && indexes.start <= i && i < indexes.end
@@ -368,7 +369,7 @@ class Content extends React.Component {
// Allow words to break if they are too long.
wordWrap: 'break-word',
// COMPAT: In iOS, a formatting menu with bold, italic and underline
// buttons is shown which causes our internal state to get out of sync in
// buttons is shown which causes our internal value to get out of sync in
// weird ways. This hides that. (2016/06/21)
...(readOnly ? {} : { WebkitUserModify: 'read-write-plaintext-only' }),
// Allow for passed-in styles to override anything.
@@ -377,7 +378,7 @@ class Content extends React.Component {
// COMPAT: In Firefox, spellchecking can remove entire wrapping elements
// including inline ones like `<a>`, which is jarring for the user but also
// causes the DOM to get into an irreconcilable state. (2016/09/01)
// causes the DOM to get into an irreconcilable value. (2016/09/01)
const spellCheck = IS_FIREFOX ? false : props.spellCheck
debug('render', { props })
@@ -432,9 +433,10 @@ class Content extends React.Component {
*/
renderNode = (child, isSelected) => {
const { editor, readOnly, schema, state } = this.props
const { document, decorations } = state
const stack = editor.getStack()
const { editor, readOnly } = this.props
const { value } = editor
const { document, decorations } = value
const { stack } = editor
let decs = document.getDecorations(stack)
if (decorations) decs = decorations.concat(decs)
return (
@@ -447,8 +449,6 @@ class Content extends React.Component {
node={child}
parent={document}
readOnly={readOnly}
schema={schema}
state={state}
/>
)
}

View File

@@ -5,7 +5,7 @@ import React from 'react'
import SlateTypes from 'slate-prop-types'
import Types from 'prop-types'
import logger from 'slate-dev-logger'
import { Schema, Stack, State } from 'slate'
import { Schema, Stack, Value } from 'slate'
import EVENT_HANDLERS from '../constants/event-handlers'
import PLUGINS_PROPS from '../constants/plugin-props'
@@ -48,9 +48,9 @@ class Editor extends React.Component {
role: Types.string,
schema: Types.object,
spellCheck: Types.bool,
state: SlateTypes.state.isRequired,
style: Types.object,
tabIndex: Types.number,
value: SlateTypes.value.isRequired,
}
/**
@@ -82,6 +82,13 @@ class Editor extends React.Component {
this.tmp.updates = 0
this.tmp.resolves = 0
let { value } = props
if (!value && props.state) {
logger.deprecate('slate-react@0.9.0', 'The `props.state` prop has been renamed to `props.value`.')
value = props.state
}
// Resolve the plugins and create a stack and schema from them.
const plugins = this.resolvePlugins(props.plugins, props.schema)
const stack = Stack.create({ plugins })
@@ -89,14 +96,13 @@ class Editor extends React.Component {
this.state.schema = schema
this.state.stack = stack
// Run `onChange` on the passed-in state because we need to ensure that it
// Run `onChange` on the passed-in value because we need to ensure that it
// is normalized, and queue the resulting change.
const change = props.state.change()
const change = value.change()
stack.run('onChange', change, this)
const { state } = change
this.queueChange(change)
this.cacheState(state)
this.state.state = state
this.cacheValue(change.value)
this.state.value = change.value
// Create a bound event handler for each event.
EVENT_HANDLERS.forEach((handler) => {
@@ -116,15 +122,20 @@ class Editor extends React.Component {
/**
* When the `props` are updated, create a new `Stack` if necessary and run
* `onChange` to ensure the state is normalized.
* `onChange` to ensure the value is normalized.
*
* @param {Object} props
*/
componentWillReceiveProps = (props) => {
let { state } = props
let { value } = props
let { schema, stack } = this.state
if (!value && props.state) {
logger.deprecate('slate-react@0.9.0', 'The `props.state` prop has been renamed to `props.value`.')
value = props.state
}
// Increment the updates counter as a baseline.
this.tmp.updates++
@@ -146,14 +157,13 @@ class Editor extends React.Component {
}
}
// Run `onChange` on the passed-in state because we need to ensure that it
// Run `onChange` on the passed-in value because we need to ensure that it
// is normalized, and queue the resulting change.
const change = state.change()
const change = value.change()
stack.run('onChange', change, this)
state = change.state
this.queueChange(change)
this.cacheState(state)
this.setState({ state })
this.cacheValue(change.value)
this.setState({ value: change.value })
}
/**
@@ -173,19 +183,19 @@ class Editor extends React.Component {
}
/**
* Cache a `state` object to be able to compare against it later.
* Cache a `value` object to be able to compare against it later.
*
* @param {State} state
* @param {Value} value
*/
cacheState = (state) => {
this.tmp.document = state.document
this.tmp.selection = state.selection
cacheValue = (value) => {
this.tmp.document = value.document
this.tmp.selection = value.selection
}
/**
* Queue a `change` object, to be able to flush it later. This is required for
* when a change needs to be applied to the state, but because of the React
* when a change needs to be applied to the value, but because of the React
* lifecycle we can't apply that change immediately. So we cache it here and
* later can call `this.flushChange()` to flush it.
*
@@ -216,6 +226,17 @@ class Editor extends React.Component {
}
}
/**
* Perform a change on the editor, passing `...args` to `change.call`.
*
* @param {Mixed} ...args
*/
change = (...args) => {
const change = this.value.change().call(...args)
this.onChange(change)
}
/**
* Programmatically blur the editor.
*/
@@ -232,6 +253,22 @@ class Editor extends React.Component {
this.change(c => c.focus())
}
/**
* Getters for exposing public properties of the editor's state.
*/
get schema() {
return this.state.schema
}
get stack() {
return this.state.stack
}
get value() {
return this.state.value
}
/**
* Get the editor's current schema.
*
@@ -239,7 +276,8 @@ class Editor extends React.Component {
*/
getSchema = () => {
return this.state.schema
logger.deprecate('slate-react@0.9.0', 'The `editor.getSchema()` method has been deprecated, use the `editor.schema` property getter instead.')
return this.schema
}
/**
@@ -249,29 +287,19 @@ class Editor extends React.Component {
*/
getStack = () => {
return this.state.stack
logger.deprecate('slate-react@0.9.0', 'The `editor.getStack()` method has been deprecated, use the `editor.stack` property getter instead.')
return this.stack
}
/**
* Get the editor's current state.
* Get the editor's current value.
*
* @return {State}
* @return {Value}
*/
getState = () => {
return this.state.state
}
/**
* Perform a change on the editor, passing `...args` to `change.call`.
*
* @param {Mixed} ...args
*/
change = (...args) => {
const { state } = this.state
const change = state.change().call(...args)
this.onChange(change)
logger.deprecate('slate-react@0.9.0', 'The `editor.getState()` method has been deprecated, use the `editor.value` property getter instead.')
return this.value
}
/**
@@ -282,10 +310,9 @@ class Editor extends React.Component {
*/
onEvent = (handler, event) => {
const { stack, state } = this.state
const change = state.change()
stack.run(handler, event, change, this)
this.onChange(change)
this.change((change) => {
this.stack.run(handler, event, change, this)
})
}
/**
@@ -297,20 +324,20 @@ class Editor extends React.Component {
onChange = (change) => {
debug('onChange', { change })
if (State.isState(change)) {
throw new Error('As of slate@0.22.0 the `editor.onChange` method must be passed a `Change` object not a `State` object.')
if (Value.isValue(change)) {
throw new Error('As of slate@0.22.0 the `editor.onChange` method must be passed a `Change` object not a `Value` object.')
}
const { stack } = this.state
stack.run('onChange', change, this)
const { state } = change
this.stack.run('onChange', change, this)
const { value } = change
const { document, selection } = this.tmp
const { onChange, onDocumentChange, onSelectionChange } = this.props
if (value == this.value) return
if (state == this.state.state) return
onChange(change)
if (onDocumentChange && state.document != document) onDocumentChange(state.document, change)
if (onSelectionChange && state.selection != selection) onSelectionChange(state.selection, change)
if (onDocumentChange && value.document != document) onDocumentChange(value.document, change)
if (onSelectionChange && value.selection != selection) onSelectionChange(value.selection, change)
}
/**
@@ -322,13 +349,12 @@ class Editor extends React.Component {
render() {
debug('render', this)
const { stack, state } = this.state
const children = stack
.map('renderPortal', state, this)
const children = this.stack
.map('renderPortal', this.value, this)
.map((child, i) => <Portal key={i} isOpened>{child}</Portal>)
const props = { ...this.props, children }
const tree = stack.render('renderEditor', props, state, this)
const tree = this.stack.render('renderEditor', props, this)
return tree
}

View File

@@ -37,8 +37,6 @@ class Leaf extends React.Component {
node: SlateTypes.node.isRequired,
offset: Types.number.isRequired,
parent: SlateTypes.node.isRequired,
schema: SlateTypes.schema.isRequired,
state: SlateTypes.state.isRequired,
text: Types.string.isRequired,
}
@@ -65,7 +63,6 @@ class Leaf extends React.Component {
if (
props.index != this.props.index ||
props.marks != this.props.marks ||
props.schema != this.props.schema ||
props.text != this.props.text ||
props.parent != this.props.parent
) {
@@ -105,12 +102,12 @@ class Leaf extends React.Component {
*/
renderMarks() {
const { marks, schema, node, offset, text, state, editor } = this.props
const stack = editor.getStack()
const { marks, node, offset, text, editor } = this.props
const { stack } = editor
const leaf = this.renderText()
return marks.reduce((children, mark) => {
const props = { editor, mark, marks, node, offset, schema, state, text, children }
const props = { editor, mark, marks, node, offset, text, children }
const element = stack.find('renderMark', props)
return element || children
}, leaf)

View File

@@ -39,8 +39,6 @@ class Node extends React.Component {
node: SlateTypes.node.isRequired,
parent: SlateTypes.node.isRequired,
readOnly: Types.bool.isRequired,
schema: SlateTypes.schema.isRequired,
state: SlateTypes.state.isRequired,
}
/**
@@ -60,13 +58,13 @@ class Node extends React.Component {
* Should the node update?
*
* @param {Object} nextProps
* @param {Object} state
* @param {Object} value
* @return {Boolean}
*/
shouldComponentUpdate = (nextProps) => {
const { props } = this
const stack = props.editor.getStack()
const { stack } = props.editor
const shouldUpdate = stack.find('shouldNodeComponentUpdate', props, nextProps)
const n = nextProps
const p = props
@@ -94,10 +92,10 @@ class Node extends React.Component {
// for simplicity we just let them through.
if (n.node != p.node) return true
// If the selection state of the node or of some of its children has changed,
// If the selection value of the node or of some of its children has changed,
// re-render in case there is any user-land logic depends on it to render.
// if the node is selected update it, even if it was already selected: the
// selection state of some of its children could have been changed and they
// selection value of some of its children could have been changed and they
// need to be rendered again.
if (n.isSelected || p.isSelected) return true
@@ -117,9 +115,10 @@ class Node extends React.Component {
render() {
this.debug('render', this)
const { editor, isSelected, node, parent, readOnly, state } = this.props
const { selection } = state
const stack = editor.getStack()
const { editor, isSelected, node, parent, readOnly } = this.props
const { value } = editor
const { selection } = value
const { stack } = editor
const indexes = node.getSelectionIndexes(selection, isSelected)
let children = node.nodes.toArray().map((child, i) => {
const isChildSelected = !!indexes && indexes.start <= i && i < indexes.end
@@ -144,7 +143,6 @@ class Node extends React.Component {
node,
parent,
readOnly,
state
}
let placeholder = stack.find('renderPlaceholder', props)
@@ -170,9 +168,9 @@ class Node extends React.Component {
*/
renderNode = (child, isSelected) => {
const { block, decorations, editor, node, readOnly, schema, state } = this.props
const { block, decorations, editor, node, readOnly } = this.props
const { stack } = editor
const Component = child.kind == 'text' ? Text : Node
const stack = editor.getStack()
const decs = decorations.concat(node.getDecorations(stack))
return (
<Component
@@ -184,8 +182,6 @@ class Node extends React.Component {
node={child}
parent={node}
readOnly={readOnly}
schema={schema}
state={state}
/>
)
}

View File

@@ -35,8 +35,6 @@ class Text extends React.Component {
editor: Types.object.isRequired,
node: SlateTypes.node.isRequired,
parent: SlateTypes.node.isRequired,
schema: SlateTypes.schema.isRequired,
state: SlateTypes.state.isRequired,
style: Types.object,
}
@@ -67,7 +65,7 @@ class Text extends React.Component {
* Should the node update?
*
* @param {Object} nextProps
* @param {Object} state
* @param {Object} value
* @return {Boolean}
*/
@@ -104,11 +102,11 @@ class Text extends React.Component {
*/
render() {
const { props } = this
this.debug('render', { props })
this.debug('render', this)
const { decorations, node, state, style } = props
const { document } = state
const { decorations, editor, node, style } = this.props
const { value } = editor
const { document } = value
const { key } = node
const decs = decorations.filter((d) => {
@@ -146,7 +144,7 @@ class Text extends React.Component {
*/
renderLeaf = (leaves, leaf, index, offset) => {
const { block, node, parent, schema, state, editor } = this.props
const { block, node, parent, editor } = this.props
const { text, marks } = leaf
return (
@@ -160,8 +158,6 @@ class Text extends React.Component {
offset={offset}
parent={parent}
leaves={leaves}
schema={schema}
state={state}
text={text}
/>
)

View File

@@ -35,8 +35,6 @@ class Void extends React.Component {
node: SlateTypes.node.isRequired,
parent: SlateTypes.node.isRequired,
readOnly: Types.bool.isRequired,
schema: SlateTypes.schema.isRequired,
state: SlateTypes.state.isRequired,
}
/**
@@ -112,7 +110,7 @@ class Void extends React.Component {
*/
renderText = () => {
const { block, decorations, isSelected, node, readOnly, schema, state, editor } = this.props
const { block, decorations, isSelected, node, readOnly, editor } = this.props
const child = node.getFirstText()
return (
<Text
@@ -124,8 +122,6 @@ class Void extends React.Component {
node={child}
parent={node}
readOnly={readOnly}
schema={schema}
state={state}
/>
)
}

View File

@@ -1,2 +0,0 @@
This directory contains the only plugin that ships with Slate by default, which controls all of the "core" logic. For example, it handles splitting apart paragraphs when `enter` is pressed, or inserting plain text content from the clipboard on paste.

View File

@@ -75,9 +75,9 @@ function AfterPlugin() {
function onClick(event, change, editor) {
if (editor.props.readOnly) return true
const { state } = change
const { document } = state
const node = findNode(event.target, state)
const { value } = change
const { document } = value
const node = findNode(event.target, value)
const isVoid = node && (node.isVoid || document.hasVoidParent(node.key))
if (isVoid) {
@@ -137,8 +137,8 @@ function AfterPlugin() {
function onCutOrCopy(event, change, editor) {
const window = getWindow(event.target)
const native = window.getSelection()
const { state } = change
const { startKey, endKey, startText, endBlock, endInline } = state
const { value } = change
const { startKey, endKey, startText, endBlock, endInline } = value
const isVoidBlock = endBlock && endBlock.isVoid
const isVoidInline = endInline && endInline.isVoid
const isVoid = isVoidBlock || isVoidInline
@@ -148,7 +148,7 @@ function AfterPlugin() {
// Create a fake selection so that we can add a Base64-encoded copy of the
// fragment to the HTML, to decode on future pastes.
const { fragment } = state
const { fragment } = value
const encoded = Base64.serializeNode(fragment)
const range = native.getRangeAt(0)
let contents = range.cloneContents()
@@ -172,7 +172,7 @@ function AfterPlugin() {
// startText node
if ((IS_CHROME || IS_SAFARI) && !isVoid && startKey === endKey) {
const hasMarks = startText.characters
.slice(state.selection.anchorOffset, state.selection.focusOffset)
.slice(value.selection.anchorOffset, value.selection.focusOffset)
.filter(char => char.marks.size !== 0)
.size !== 0
if (hasMarks) {
@@ -279,16 +279,16 @@ function AfterPlugin() {
isDraggingInternally = true
const { state } = change
const { document } = state
const node = findNode(event.target, state)
const { value } = change
const { document } = value
const node = findNode(event.target, value)
const isVoid = node && (node.isVoid || document.hasVoidParent(node.key))
if (isVoid) {
const encoded = Base64.serializeNode(node, { preserveKeys: true })
setEventTransfer(event, 'node', encoded)
} else {
const { fragment } = state
const { fragment } = value
const encoded = Base64.serializeNode(fragment)
setEventTransfer(event, 'fragment', encoded)
}
@@ -305,9 +305,9 @@ function AfterPlugin() {
function onDrop(event, change, editor) {
debug('onDrop', { event })
const { state } = change
const { document, selection } = state
let target = getEventRange(event, state)
const { value } = change
const { document, selection } = value
let target = getEventRange(event, value)
if (!target) return
const transfer = getEventTransfer(event)
@@ -395,16 +395,16 @@ function AfterPlugin() {
debug('onInput', { event })
const window = getWindow(event.target)
const { state } = change
const { value } = change
// Get the selection point.
const native = window.getSelection()
const { anchorNode, anchorOffset } = native
const point = findPoint(anchorNode, anchorOffset, state)
const point = findPoint(anchorNode, anchorOffset, value)
if (!point) return
// Get the text node and leaf in question.
const { document, selection } = state
const { document, selection } = value
const node = document.getDescendant(point.key)
const leaves = node.getLeaves()
let start = 0
@@ -441,7 +441,7 @@ function AfterPlugin() {
const corrected = selection.collapseToEnd().move(delta)
const entire = selection.moveAnchorTo(point.key, start).moveFocusTo(point.key, end)
// Change the current state to have the leaf's text replaced.
// Change the current value to have the leaf's text replaced.
change
.select(entire)
.delete()
@@ -460,10 +460,10 @@ function AfterPlugin() {
function onKeyDown(event, change, editor) {
debug('onKeyDown', { event })
const { state } = change
const { value } = change
if (HOTKEYS.SPLIT_BLOCK(event)) {
return state.isInVoid
return value.isInVoid
? change.collapseToStartOfNextText()
: change.splitBlock()
}
@@ -527,7 +527,7 @@ function AfterPlugin() {
// an inline is selected, we need to handle these hotkeys manually because
// browsers won't know what to do.
if (HOTKEYS.COLLAPSE_CHAR_BACKWARD(event)) {
const { document, isInVoid, previousText, startText } = state
const { document, isInVoid, previousText, startText } = value
const isPreviousInVoid = previousText && document.hasVoidParent(previousText.key)
if (isInVoid || isPreviousInVoid || startText.text == '') {
event.preventDefault()
@@ -536,7 +536,7 @@ function AfterPlugin() {
}
if (HOTKEYS.COLLAPSE_CHAR_FORWARD(event)) {
const { document, isInVoid, nextText, startText } = state
const { document, isInVoid, nextText, startText } = value
const isNextInVoid = nextText && document.hasVoidParent(nextText.key)
if (isInVoid || isNextInVoid || startText.text == '') {
event.preventDefault()
@@ -545,7 +545,7 @@ function AfterPlugin() {
}
if (HOTKEYS.EXTEND_CHAR_BACKWARD(event)) {
const { document, isInVoid, previousText, startText } = state
const { document, isInVoid, previousText, startText } = value
const isPreviousInVoid = previousText && document.hasVoidParent(previousText.key)
if (isInVoid || isPreviousInVoid || startText.text == '') {
event.preventDefault()
@@ -554,7 +554,7 @@ function AfterPlugin() {
}
if (HOTKEYS.EXTEND_CHAR_FORWARD(event)) {
const { document, isInVoid, nextText, startText } = state
const { document, isInVoid, nextText, startText } = value
const isNextInVoid = nextText && document.hasVoidParent(nextText.key)
if (isInVoid || isNextInVoid || startText.text == '') {
event.preventDefault()
@@ -582,8 +582,8 @@ function AfterPlugin() {
}
if (type == 'text' || type == 'html') {
const { state } = change
const { document, selection, startBlock } = state
const { value } = change
const { document, selection, startBlock } = value
if (startBlock.isVoid) return
const defaultBlock = startBlock
@@ -605,8 +605,8 @@ function AfterPlugin() {
debug('onSelect', { event })
const window = getWindow(event.target)
const { state } = change
const { document } = state
const { value } = change
const { document } = value
const native = window.getSelection()
// If there are no ranges, the editor was blurred natively.
@@ -616,7 +616,7 @@ function AfterPlugin() {
}
// Otherwise, determine the Slate selection from the native one.
let range = findRange(native, state)
let range = findRange(native, value)
if (!range) return
const { anchorKey, anchorOffset, focusKey, focusOffset } = range
@@ -676,12 +676,11 @@ function AfterPlugin() {
* Render editor.
*
* @param {Object} props
* @param {State} state
* @param {Editor} editor
* @return {Object}
*/
function renderEditor(props, state, editor) {
function renderEditor(props, editor) {
const handlers = EVENT_HANDLERS.reduce((obj, handler) => {
obj[handler] = editor[handler]
return obj
@@ -697,9 +696,7 @@ function AfterPlugin() {
editor={editor}
readOnly={props.readOnly}
role={props.role}
schema={editor.getSchema()}
spellCheck={props.spellCheck}
state={state}
style={props.style}
tabIndex={props.tabIndex}
tagName={props.tagName}
@@ -730,11 +727,11 @@ function AfterPlugin() {
*/
function renderPlaceholder(props) {
const { editor, node, state } = props
const { editor, node } = props
if (node.kind != 'block') return
if (!Text.isTextList(node.nodes)) return
if (node.text != '') return
if (state.document.getBlocks().size > 1) return
if (editor.value.document.getBlocks().size > 1) return
const style = {
pointerEvents: 'none',

View File

@@ -61,7 +61,7 @@ function BeforePlugin() {
if (isCopying) return true
if (editor.props.readOnly) return true
const { state } = change
const { value } = change
const focusTarget = event.relatedTarget
// If focusTarget is null, the blur event is due to the window itself being
@@ -82,7 +82,7 @@ function BeforePlugin() {
// (eg. a list item of the check list example).
if (
el.contains(focusTarget) &&
!findNode(focusTarget, state).isVoid
!findNode(focusTarget, value).isVoid
) {
return true
}
@@ -98,13 +98,13 @@ function BeforePlugin() {
*/
function onChange(change, editor) {
const { state } = change
const schema = editor.getSchema()
const { value } = change
// If the state's schema isn't the editor's schema, update it.
if (state.schema != schema) {
// If the value's schema isn't the editor's schema, update it. This can
// happen on the initialization of the editor, or if the schema changes.
if (value.schema != editor.schema) {
change
.setState({ schema })
.setValue({ schema: editor.schema })
.normalize()
}
@@ -282,7 +282,7 @@ function BeforePlugin() {
// Nothing happens in read-only mode.
if (editor.props.readOnly) return true
// Prevent default so the DOM's state isn't corrupted.
// Prevent default so the DOM's value isn't corrupted.
event.preventDefault()
debug('onDrop', { event })
@@ -323,7 +323,7 @@ function BeforePlugin() {
function onInput(event, change, editor) {
if (isComposing) return true
if (change.state.isBlurred) return true
if (change.value.isBlurred) return true
debug('onInput', { event })
}
@@ -348,7 +348,7 @@ function BeforePlugin() {
}
// Certain hotkeys have native behavior in contenteditable elements which
// will cause our state to be out of sync, so prevent them.
// will cause our value to be out of sync, so prevent them.
if (HOTKEYS.CONTENTEDITABLE(event)) {
event.preventDefault()
}

View File

@@ -3,17 +3,18 @@
* Find a Slate node from a DOM `element`.
*
* @param {Element} element
* @param {Value} value
* @return {Node|Null}
*/
function findNode(element, state) {
function findNode(element, value) {
const closest = element.closest('[data-key]')
if (!closest) return null
const key = closest.getAttribute('data-key')
if (!key) return null
const node = state.document.getNode(key)
const node = value.document.getNode(key)
return node || null
}

View File

@@ -19,11 +19,11 @@ const VOID_SELECTOR = '[data-slate-void]'
*
* @param {Element} nativeNode
* @param {Number} nativeOffset
* @param {State} state
* @param {Value} value
* @return {Object}
*/
function findPoint(nativeNode, nativeOffset, state) {
function findPoint(nativeNode, nativeOffset, value) {
const {
node: nearestNode,
offset: nearestOffset,
@@ -71,7 +71,7 @@ function findPoint(nativeNode, nativeOffset, state) {
// COMPAT: If someone is clicking from one Slate editor into another, the
// select event fires twice, once for the old editor's `element` first, and
// then afterwards for the correct `element`. (2017/03/03)
if (!state.document.hasDescendant(key)) return null
if (!value.document.hasDescendant(key)) return null
return {
key,

View File

@@ -9,11 +9,11 @@ import findPoint from './find-point'
* Find a Slate range from a DOM `native` selection.
*
* @param {Selection} native
* @param {State} state
* @param {Value} value
* @return {Range}
*/
function findRange(native, state) {
function findRange(native, value) {
const el = native.anchorNode || native.startContainer
if (!el) return null
@@ -31,8 +31,8 @@ function findRange(native, state) {
}
const { anchorNode, anchorOffset, focusNode, focusOffset, isCollapsed } = native
const anchor = findPoint(anchorNode, anchorOffset, state)
const focus = isCollapsed ? anchor : findPoint(focusNode, focusOffset, state)
const anchor = findPoint(anchorNode, anchorOffset, value)
const focus = isCollapsed ? anchor : findPoint(focusNode, focusOffset, value)
if (!anchor || !focus) return null
const range = Range.create({

View File

@@ -8,11 +8,11 @@ import findRange from './find-range'
* Get the target range from a DOM `event`.
*
* @param {Event} event
* @param {State} state
* @param {Value} value
* @return {Range}
*/
function getEventRange(event, state) {
function getEventRange(event, value) {
if (event.nativeEvent) {
event = event.nativeEvent
}
@@ -35,10 +35,10 @@ function getEventRange(event, state) {
}
// Resolve a Slate range from the DOM range.
let range = findRange(r, state)
let range = findRange(r, value)
if (!range) return null
const { document } = state
const { document } = value
const node = document.getNode(range.anchorKey)
const parent = document.getParent(node.key)
const el = findDOMNode(parent)

View File

@@ -7,19 +7,19 @@ export default function (simulator) {
}
export const input = (
<state>
<value>
<document>
<paragraph />
</document>
<selection isFocused />
</state>
</value>
)
export const output = (
<state>
<value>
<document>
<paragraph />
</document>
<selection isFocused={false} />
</state>
</value>
)

View File

@@ -7,22 +7,22 @@ export default function (simulator) {
}
export const input = (
<state>
<value>
<document>
<paragraph>
<cursor />
</paragraph>
</document>
</state>
</value>
)
export const output = (
<state>
<value>
<document>
<paragraph />
<paragraph>
<cursor />
</paragraph>
</document>
</state>
</value>
)

View File

@@ -4,28 +4,28 @@ import h from '../../../helpers/h'
import { Range } from 'slate'
export default function (simulator) {
const { state } = simulator
const text = state.document.getTexts().first()
const { value } = simulator
const text = value.document.getTexts().first()
const selection = Range.create().collapseToStartOf(text).move(1).focus()
simulator.select(null, { selection })
}
export const input = (
<state>
<value>
<document>
<paragraph>
<cursor />word
</paragraph>
</document>
</state>
</value>
)
export const output = (
<state>
<value>
<document>
<paragraph>
w<cursor />ord
</paragraph>
</document>
</state>
</value>
)

View File

@@ -27,10 +27,10 @@ describe('plugins', () => {
const { input, output, props = {}} = module
const fn = module.default
const plugins = [BeforePlugin(props), AfterPlugin(props)]
const simulator = new Simulator({ plugins, state: input })
const simulator = new Simulator({ plugins, value: input })
fn(simulator)
const actual = simulator.state.toJSON({ preserveSelection: true })
const actual = simulator.value.toJSON({ preserveSelection: true })
const expected = output.toJSON({ preserveSelection: true })
assert.deepEqual(actual, expected)
})

View File

@@ -21,8 +21,8 @@ export const props = {
renderNode,
}
export const state = (
<state>
export const value = (
<value>
<document>
<code>
word
@@ -34,7 +34,7 @@ export const state = (
word
</code>
</document>
</state>
</value>
)
export const output = `

View File

@@ -19,12 +19,12 @@ export const props = {
renderNode,
}
export const state = (
<state>
export const value = (
<value>
<document>
<image src="https://example.com/image.png" />
</document>
</state>
</value>
)
export const output = `

View File

@@ -19,14 +19,14 @@ export const props = {
}
}
export const state = (
<state>
export const value = (
<value>
<document>
<code>
word
</code>
</document>
</state>
</value>
)
export const output = `

View File

@@ -29,14 +29,14 @@ export const props = {
renderMark,
}
export const state = (
<state>
export const value = (
<value>
<document>
<paragraph>
one
</paragraph>
</document>
</state>
</value>
)
export const output = `

View File

@@ -19,8 +19,8 @@ export const props = {
renderNode,
}
export const state = (
<state>
export const value = (
<value>
<document>
<paragraph>
<link href="https://google.com">
@@ -34,7 +34,7 @@ export const state = (
</link>
</paragraph>
</document>
</state>
</value>
)
export const output = `

View File

@@ -19,14 +19,14 @@ export const props = {
renderNode,
}
export const state = (
<state>
export const value = (
<value>
<document>
<paragraph>
<emoji />
</paragraph>
</document>
</state>
</value>
)
export const output = `

View File

@@ -19,8 +19,8 @@ export const props = {
renderNode,
}
export const state = (
<state>
export const value = (
<value>
<document>
<paragraph>
<link href="https://google.com">
@@ -28,7 +28,7 @@ export const state = (
</link>
</paragraph>
</document>
</state>
</value>
)
export const output = `

View File

@@ -17,14 +17,14 @@ export const props = {
renderMark,
}
export const state = (
<state>
export const value = (
<value>
<document>
<paragraph>
one<b>two</b>three
</paragraph>
</document>
</state>
</value>
)
export const output = `

View File

@@ -4,8 +4,8 @@ import h from '../../helpers/h'
export const props = {}
export const state = (
<state>
export const value = (
<value>
<document>
<paragraph>
<link>
@@ -13,7 +13,7 @@ export const state = (
</link>
</paragraph>
</document>
</state>
</value>
)
export const output = `

View File

@@ -4,14 +4,14 @@ import h from '../../helpers/h'
export const props = {}
export const state = (
<state>
export const value = (
<value>
<document>
<paragraph>
word
</paragraph>
</document>
</state>
</value>
)
export const output = `

View File

@@ -4,14 +4,14 @@ import h from '../../helpers/h'
export const props = {}
export const state = (
<state>
export const value = (
<value>
<document>
<paragraph>
<link />
</paragraph>
</document>
</state>
</value>
)
export const output = `

View File

@@ -4,12 +4,12 @@ import h from '../../helpers/h'
export const props = {}
export const state = (
<state>
export const value = (
<value>
<document>
<paragraph />
</document>
</state>
</value>
)
export const output = `

View File

@@ -4,8 +4,8 @@ import h from '../../helpers/h'
export const props = {}
export const state = (
<state>
export const value = (
<value>
<document>
<quote>
<paragraph>
@@ -16,7 +16,7 @@ export const state = (
</paragraph>
</quote>
</document>
</state>
</value>
)
export const output = `

View File

@@ -18,12 +18,12 @@ export const props = {
renderNode,
}
export const state = (
<state>
export const value = (
<value>
<document>
<image src="https://example.com/image.png" />
</document>
</state>
</value>
)
export const output = `

View File

@@ -20,14 +20,14 @@ export const props = {
renderNode,
}
export const state = (
<state>
export const value = (
<value>
<document>
<paragraph>
<emoji />
</paragraph>
</document>
</state>
</value>
)
export const output = `

View File

@@ -4,8 +4,8 @@ import h from '../../helpers/h'
export const props = {}
export const state = (
<state>
export const value = (
<value>
<document>
<paragraph>
Hello, world!
@@ -17,7 +17,7 @@ export const state = (
שלום עולם
</paragraph>
</document>
</state>
</value>
)
export const output = `

View File

@@ -19,9 +19,9 @@ describe('rendering', () => {
for (const test of tests) {
it(test, async () => {
const module = require(resolve(dir, test))
const { state, output, props } = module
const { value, output, props } = module
const p = {
state,
value,
onChange() {},
...(props || {}),
}