mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-30 10:29:48 +02:00
Add controller (#2221)
* fold Stack into Editor * switch Change objects to be tied to editors, not values * introduce controller * add the "commands" concept * convert history into commands on `value.data` * add the ability to not normalize on editor creation/setting * convert schema to a mutable constructor * add editor.command method * convert plugin handlers to receive `next` * switch commands to use the onCommand middleware * add queries support, convert schema to queries * split out browser plugin * remove noop util * fixes * fixes * start fixing tests, refactor hyperscript to be more literal * fix slate-html-serializer tests * fix schema tests with hyperscript * fix text model tests with hyperscript * fix more tests * get all tests passing * fix lint * undo decorations example update * update examples * small changes to the api to make it nicer * update docs * update commands/queries plugin logic * change normalizeNode and validateNode to be middleware * fix decoration removal * rename commands tests * add useful errors to existing APIs * update changelogs * cleanup * fixes * update docs * add editor docs
This commit is contained in:
@@ -4,6 +4,68 @@ This document maintains a list of changes to the `slate-hyperscript` package wit
|
||||
|
||||
---
|
||||
|
||||
### `0.11.0` — October 9, 2018
|
||||
|
||||
###### BREAKING
|
||||
|
||||
**Updated to the latest version of `slate`.** The `slate-hyperscript` codebase has been updated to be compatible with the latest version of `slate`, `0.42.0`. This is a backward incompatible upgrade, and so the peer dependency range has been bumped.
|
||||
|
||||
**`slate-hyperscript` no longer normalizes values.** This behavior was very problematic because it meant that you could not determine exactly what output you'd receive from any given hyperscript creation. The logic for creating child nodes was inconsistent, relying on the built-in normalization to help keep it "normal". While this is sometimes helpful, it makes writing tests for invalid states very tricky, if not impossible.
|
||||
|
||||
Now, `slate-hyperscript` does not do any normalization, meaning that you can create any document structure with it. For example, you can create a block node inside an inline node, even though a Slate editor wouldn't allow it. Or, if you don't create leaf text nodes, they won't exist in the output.
|
||||
|
||||
For example these are no longer equivalent:
|
||||
|
||||
```jsx
|
||||
<document>
|
||||
<paragraph>
|
||||
<link>word</link>
|
||||
</paragraph>
|
||||
</document>
|
||||
```
|
||||
|
||||
```jsx
|
||||
<document>
|
||||
<paragraph>
|
||||
<text />
|
||||
<link>word</link>
|
||||
<text />
|
||||
</paragraph>
|
||||
</document>
|
||||
```
|
||||
|
||||
Similarly, these are no longer equivalent either:
|
||||
|
||||
```jsx
|
||||
<document>
|
||||
<paragraph />
|
||||
</document>
|
||||
```
|
||||
|
||||
```jsx
|
||||
<document>
|
||||
<paragraph>
|
||||
<text />
|
||||
</paragraph>
|
||||
</document>
|
||||
```
|
||||
|
||||
This allows you to much more easily test invalid states and transition states. However, it means that you need to be more explicit in the "normal" states than previously.
|
||||
|
||||
**The `<text>` and `<mark>` creators now return useful objects.** This is a related change that makes the library more useful. Previously you could expect to receive a `value` from the `<value>` creator, but the others were less consistent. For example, the `<text>` creator would actually return an array, instead of the `Text` node that you expect.
|
||||
|
||||
```js
|
||||
// Previously you had to do...
|
||||
const text = <text>word</text>[0]
|
||||
|
||||
// But now it's more obvious...
|
||||
const text = <text>word</text>
|
||||
```
|
||||
|
||||
Similarly, the `mark` creator used to return a `Text` node. Now it returns a list of `Leaf` objects, which can be passed directly as children to the `<text>` creator.
|
||||
|
||||
---
|
||||
|
||||
### `0.10.0` — August 22, 2018
|
||||
|
||||
###### BREAKING
|
||||
|
530
packages/slate-hyperscript/src/creators.js
Normal file
530
packages/slate-hyperscript/src/creators.js
Normal file
@@ -0,0 +1,530 @@
|
||||
import {
|
||||
Decoration,
|
||||
Document,
|
||||
Leaf,
|
||||
Mark,
|
||||
Node,
|
||||
Point,
|
||||
Selection,
|
||||
Text,
|
||||
Value,
|
||||
} from 'slate'
|
||||
|
||||
/**
|
||||
* Auto-incrementing ID to keep track of paired decorations.
|
||||
*
|
||||
* @type {Number}
|
||||
*/
|
||||
|
||||
let uid = 0
|
||||
|
||||
/**
|
||||
* Create an anchor point.
|
||||
*
|
||||
* @param {String} tagName
|
||||
* @param {Object} attributes
|
||||
* @param {Array} children
|
||||
* @return {AnchorPoint}
|
||||
*/
|
||||
|
||||
export function createAnchor(tagName, attributes, children) {
|
||||
return new AnchorPoint(attributes)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a block.
|
||||
*
|
||||
* @param {String} tagName
|
||||
* @param {Object} attributes
|
||||
* @param {Array} children
|
||||
* @return {Block}
|
||||
*/
|
||||
|
||||
export function createBlock(tagName, attributes, children) {
|
||||
const attrs = { ...attributes, object: 'block' }
|
||||
const block = createNode('node', attrs, children)
|
||||
return block
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a cursor point.
|
||||
*
|
||||
* @param {String} tagName
|
||||
* @param {Object} attributes
|
||||
* @param {Array} children
|
||||
* @return {CursorPoint}
|
||||
*/
|
||||
|
||||
export function createCursor(tagName, attributes, children) {
|
||||
return new CursorPoint(attributes)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a decoration point, or wrap a list of leaves and set the decoration
|
||||
* point tracker on them.
|
||||
*
|
||||
* @param {String} tagName
|
||||
* @param {Object} attributes
|
||||
* @param {Array} children
|
||||
* @return {DecorationPoint|List<Leaf>}
|
||||
*/
|
||||
|
||||
export function createDecoration(tagName, attributes, children) {
|
||||
const { key, data } = attributes
|
||||
const type = tagName
|
||||
|
||||
if (key) {
|
||||
return new DecorationPoint({ id: key, type, data })
|
||||
}
|
||||
|
||||
const leaves = createLeaves('leaves', {}, children)
|
||||
const first = leaves.first()
|
||||
const last = leaves.last()
|
||||
const id = `__decoration_${uid++}__`
|
||||
const start = new DecorationPoint({ id, type, data })
|
||||
const end = new DecorationPoint({ id, type, data })
|
||||
setPoint(first, start, 0)
|
||||
setPoint(last, end, last.text.length)
|
||||
return leaves
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a document.
|
||||
*
|
||||
* @param {String} tagName
|
||||
* @param {Object} attributes
|
||||
* @param {Array} children
|
||||
* @return {Document}
|
||||
*/
|
||||
|
||||
export function createDocument(tagName, attributes, children) {
|
||||
const attrs = { ...attributes, object: 'document' }
|
||||
const document = createNode('node', attrs, children)
|
||||
return document
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a focus point.
|
||||
*
|
||||
* @param {String} tagName
|
||||
* @param {Object} attributes
|
||||
* @param {Array} children
|
||||
* @return {FocusPoint}
|
||||
*/
|
||||
|
||||
export function createFocus(tagName, attributes, children) {
|
||||
return new FocusPoint(attributes)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an inline.
|
||||
*
|
||||
* @param {String} tagName
|
||||
* @param {Object} attributes
|
||||
* @param {Array} children
|
||||
* @return {Inline}
|
||||
*/
|
||||
|
||||
export function createInline(tagName, attributes, children) {
|
||||
const attrs = { ...attributes, object: 'inline' }
|
||||
const inline = createNode('node', attrs, children)
|
||||
return inline
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a list of leaves.
|
||||
*
|
||||
* @param {String} tagName
|
||||
* @param {Object} attributes
|
||||
* @param {Array} children
|
||||
* @return {List<Leaf>}
|
||||
*/
|
||||
|
||||
export function createLeaves(tagName, attributes, children) {
|
||||
const { marks = Mark.createSet() } = attributes
|
||||
let length = 0
|
||||
let leaves = Leaf.createList([])
|
||||
let leaf
|
||||
|
||||
children.forEach(child => {
|
||||
if (Leaf.isLeafList(child)) {
|
||||
if (leaf) {
|
||||
leaves = leaves.push(leaf)
|
||||
leaf = null
|
||||
}
|
||||
|
||||
child.forEach(l => {
|
||||
l = preservePoint(l, obj => obj.addMarks(marks))
|
||||
leaves = leaves.push(l)
|
||||
})
|
||||
} else {
|
||||
if (!leaf) {
|
||||
leaf = Leaf.create({ marks, text: '' })
|
||||
length = 0
|
||||
}
|
||||
|
||||
if (typeof child === 'string') {
|
||||
const offset = leaf.text.length
|
||||
leaf = preservePoint(leaf, obj => obj.insertText(offset, child))
|
||||
length += child.length
|
||||
}
|
||||
|
||||
if (isPoint(child)) {
|
||||
setPoint(leaf, child, length)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (!leaves.size && !leaf) {
|
||||
leaf = Leaf.create({ marks, text: '' })
|
||||
}
|
||||
|
||||
if (leaf) {
|
||||
leaves = leaves.push(leaf)
|
||||
}
|
||||
|
||||
return leaves
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a list of leaves from a mark.
|
||||
*
|
||||
* @param {String} tagName
|
||||
* @param {Object} attributes
|
||||
* @param {Array} children
|
||||
* @return {List<Leaf>}
|
||||
*/
|
||||
|
||||
export function createMark(tagName, attributes, children) {
|
||||
const marks = Mark.createSet([attributes])
|
||||
const leaves = createLeaves('leaves', { marks }, children)
|
||||
return leaves
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a node.
|
||||
*
|
||||
* @param {String} tagName
|
||||
* @param {Object} attributes
|
||||
* @param {Array} children
|
||||
* @return {Node}
|
||||
*/
|
||||
|
||||
export function createNode(tagName, attributes, children) {
|
||||
const { object } = attributes
|
||||
|
||||
if (object === 'text') {
|
||||
return createText('text', {}, children)
|
||||
}
|
||||
|
||||
const nodes = []
|
||||
let others = []
|
||||
|
||||
children.forEach(child => {
|
||||
if (Node.isNode(child)) {
|
||||
if (others.length) {
|
||||
const text = createText('text', {}, others)
|
||||
nodes.push(text)
|
||||
}
|
||||
|
||||
nodes.push(child)
|
||||
others = []
|
||||
} else {
|
||||
others.push(child)
|
||||
}
|
||||
})
|
||||
|
||||
if (others.length) {
|
||||
const text = createText('text', {}, others)
|
||||
nodes.push(text)
|
||||
}
|
||||
|
||||
const node = Node.create({ ...attributes, nodes })
|
||||
return node
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a selection.
|
||||
*
|
||||
* @param {String} tagName
|
||||
* @param {Object} attributes
|
||||
* @param {Array} children
|
||||
* @return {Selection}
|
||||
*/
|
||||
|
||||
export function createSelection(tagName, attributes, children) {
|
||||
const anchor = children.find(c => c instanceof AnchorPoint)
|
||||
const focus = children.find(c => c instanceof FocusPoint)
|
||||
const { marks, focused } = attributes
|
||||
const selection = Selection.create({
|
||||
marks,
|
||||
isFocused: focused,
|
||||
anchor: anchor && {
|
||||
key: anchor.key,
|
||||
offset: anchor.offset,
|
||||
path: anchor.path,
|
||||
},
|
||||
focus: focus && {
|
||||
key: focus.key,
|
||||
offset: focus.offset,
|
||||
path: focus.path,
|
||||
},
|
||||
})
|
||||
|
||||
return selection
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a text node.
|
||||
*
|
||||
* @param {String} tagName
|
||||
* @param {Object} attributes
|
||||
* @param {Array} children
|
||||
* @return {Text}
|
||||
*/
|
||||
|
||||
export function createText(tagName, attributes, children) {
|
||||
const { key } = attributes
|
||||
const leaves = createLeaves('leaves', {}, children)
|
||||
const text = Text.create({ key, leaves })
|
||||
let length = 0
|
||||
|
||||
leaves.forEach(leaf => {
|
||||
incrementPoint(leaf, length)
|
||||
preservePoint(leaf, () => text)
|
||||
length += leaf.text.length
|
||||
})
|
||||
|
||||
return text
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a value.
|
||||
*
|
||||
* @param {String} tagName
|
||||
* @param {Object} attributes
|
||||
* @param {Array} children
|
||||
* @return {Value}
|
||||
*/
|
||||
|
||||
export function createValue(tagName, attributes, children) {
|
||||
const { data } = attributes
|
||||
const document = children.find(Document.isDocument)
|
||||
let selection = children.find(Selection.isSelection)
|
||||
let anchor
|
||||
let focus
|
||||
let decorations = []
|
||||
const partials = {}
|
||||
|
||||
// Search the document's texts to see if any of them have the anchor or
|
||||
// focus information saved, or decorations applied.
|
||||
if (document) {
|
||||
document.getTexts().forEach(text => {
|
||||
if (text.__anchor != null) {
|
||||
anchor = Point.create({ key: text.key, offset: text.__anchor.offset })
|
||||
}
|
||||
|
||||
if (text.__focus != null) {
|
||||
focus = Point.create({ key: text.key, offset: text.__focus.offset })
|
||||
}
|
||||
|
||||
if (text.__decorations != null) {
|
||||
for (const dec of text.__decorations) {
|
||||
const { id } = dec
|
||||
const partial = partials[id]
|
||||
delete partials[id]
|
||||
|
||||
if (!partial) {
|
||||
dec.key = text.key
|
||||
partials[id] = dec
|
||||
continue
|
||||
}
|
||||
|
||||
const decoration = Decoration.create({
|
||||
anchor: {
|
||||
key: partial.key,
|
||||
offset: partial.offset,
|
||||
},
|
||||
focus: {
|
||||
key: text.key,
|
||||
offset: dec.offset,
|
||||
},
|
||||
mark: {
|
||||
type: dec.type,
|
||||
data: dec.data,
|
||||
},
|
||||
})
|
||||
|
||||
decorations.push(decoration)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (Object.keys(partials).length > 0) {
|
||||
throw new Error(
|
||||
`Slate hyperscript must have both a start and an end defined for each decoration using the \`key=\` prop.`
|
||||
)
|
||||
}
|
||||
|
||||
if (anchor && !focus) {
|
||||
throw new Error(
|
||||
`Slate hyperscript ranges must have both \`<anchor />\` and \`<focus />\` defined if one is defined, but you only defined \`<anchor />\`. For collapsed selections, use \`<cursor />\` instead.`
|
||||
)
|
||||
}
|
||||
|
||||
if (!anchor && focus) {
|
||||
throw new Error(
|
||||
`Slate hyperscript ranges must have both \`<anchor />\` and \`<focus />\` defined if one is defined, but you only defined \`<focus />\`. For collapsed selections, use \`<cursor />\` instead.`
|
||||
)
|
||||
}
|
||||
|
||||
if (anchor || focus) {
|
||||
if (!selection) {
|
||||
selection = Selection.create({ anchor, focus, isFocused: true })
|
||||
} else {
|
||||
selection = selection.setPoints([anchor, focus])
|
||||
}
|
||||
} else if (!selection) {
|
||||
selection = Selection.create()
|
||||
}
|
||||
|
||||
selection = selection.normalize(document)
|
||||
|
||||
if (decorations.length > 0) {
|
||||
decorations = decorations.map(d => d.normalize(document))
|
||||
}
|
||||
|
||||
const value = Value.fromJSON({
|
||||
data,
|
||||
decorations,
|
||||
document,
|
||||
selection,
|
||||
...attributes,
|
||||
})
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
/**
|
||||
* Point classes that can be created at different points in the document and
|
||||
* then searched for afterwards, for creating ranges.
|
||||
*
|
||||
* @type {Class}
|
||||
*/
|
||||
|
||||
class CursorPoint {
|
||||
constructor() {
|
||||
this.offset = null
|
||||
}
|
||||
}
|
||||
|
||||
class AnchorPoint {
|
||||
constructor(attrs = {}) {
|
||||
const { key = null, offset = null, path = null } = attrs
|
||||
this.key = key
|
||||
this.offset = offset
|
||||
this.path = path
|
||||
}
|
||||
}
|
||||
|
||||
class FocusPoint {
|
||||
constructor(attrs = {}) {
|
||||
const { key = null, offset = null, path = null } = attrs
|
||||
this.key = key
|
||||
this.offset = offset
|
||||
this.path = path
|
||||
}
|
||||
}
|
||||
|
||||
class DecorationPoint {
|
||||
constructor(attrs) {
|
||||
const { id = null, data = {}, type } = attrs
|
||||
this.id = id
|
||||
this.offset = null
|
||||
this.type = type
|
||||
this.data = data
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment any existing `point` on object by `n`.
|
||||
*
|
||||
* @param {Any} object
|
||||
* @param {Number} n
|
||||
*/
|
||||
|
||||
function incrementPoint(object, n) {
|
||||
const { __anchor, __focus, __decorations } = object
|
||||
|
||||
if (__anchor != null) {
|
||||
__anchor.offset += n
|
||||
}
|
||||
|
||||
if (__focus != null && __focus !== __anchor) {
|
||||
__focus.offset += n
|
||||
}
|
||||
|
||||
if (__decorations != null) {
|
||||
__decorations.forEach(d => (d.offset += n))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an `object` is a point.
|
||||
*
|
||||
* @param {Any} object
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
function isPoint(object) {
|
||||
return (
|
||||
object instanceof AnchorPoint ||
|
||||
object instanceof CursorPoint ||
|
||||
object instanceof DecorationPoint ||
|
||||
object instanceof FocusPoint
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Preserve any point information on an object.
|
||||
*
|
||||
* @param {Any} object
|
||||
* @param {Function} updator
|
||||
* @return {Any}
|
||||
*/
|
||||
|
||||
function preservePoint(object, updator) {
|
||||
const { __anchor, __focus, __decorations } = object
|
||||
const next = updator(object)
|
||||
if (__anchor != null) next.__anchor = __anchor
|
||||
if (__focus != null) next.__focus = __focus
|
||||
if (__decorations != null) next.__decorations = __decorations
|
||||
return next
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a `point` on an `object`.
|
||||
*
|
||||
* @param {Any} object
|
||||
* @param {*Point} point
|
||||
* @param {Number} offset
|
||||
*/
|
||||
|
||||
function setPoint(object, point, offset) {
|
||||
if (point instanceof AnchorPoint || point instanceof CursorPoint) {
|
||||
point.offset = offset
|
||||
object.__anchor = point
|
||||
}
|
||||
|
||||
if (point instanceof FocusPoint || point instanceof CursorPoint) {
|
||||
point.offset = offset
|
||||
object.__focus = point
|
||||
}
|
||||
|
||||
if (point instanceof DecorationPoint) {
|
||||
point.offset = offset
|
||||
object.__decorations = object.__decorations || []
|
||||
object.__decorations = object.__decorations.concat(point)
|
||||
}
|
||||
}
|
@@ -1,286 +1,19 @@
|
||||
import isPlainObject from 'is-plain-object'
|
||||
|
||||
import {
|
||||
Block,
|
||||
Decoration,
|
||||
Document,
|
||||
Inline,
|
||||
Mark,
|
||||
Node,
|
||||
Point,
|
||||
Selection,
|
||||
Text,
|
||||
Value,
|
||||
} from 'slate'
|
||||
|
||||
/**
|
||||
* Point classes that can be created at different points in the document and
|
||||
* then searched for afterwards, for creating ranges.
|
||||
*
|
||||
* @type {Class}
|
||||
*/
|
||||
|
||||
class CursorPoint {
|
||||
constructor() {
|
||||
this.offset = null
|
||||
}
|
||||
}
|
||||
|
||||
class AnchorPoint {
|
||||
constructor(attrs = {}) {
|
||||
const { key = null, offset = null, path = null } = attrs
|
||||
this.key = key
|
||||
this.offset = offset
|
||||
this.path = path
|
||||
}
|
||||
}
|
||||
|
||||
class FocusPoint {
|
||||
constructor(attrs = {}) {
|
||||
const { key = null, offset = null, path = null } = attrs
|
||||
this.key = key
|
||||
this.offset = offset
|
||||
this.path = path
|
||||
}
|
||||
}
|
||||
|
||||
class DecorationPoint {
|
||||
constructor(attrs) {
|
||||
const { key = null, data = {}, type } = attrs
|
||||
this.id = key
|
||||
this.offset = 0
|
||||
this.type = type
|
||||
this.data = data
|
||||
}
|
||||
|
||||
combine = focus => {
|
||||
if (!(focus instanceof DecorationPoint)) {
|
||||
throw new Error('misaligned decorations')
|
||||
}
|
||||
|
||||
return Decoration.create({
|
||||
anchor: {
|
||||
key: this.key,
|
||||
offset: this.offset,
|
||||
},
|
||||
focus: {
|
||||
key: focus.key,
|
||||
offset: focus.offset,
|
||||
},
|
||||
mark: {
|
||||
type: this.type,
|
||||
data: this.data,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The default Slate hyperscript creator functions.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
|
||||
const CREATORS = {
|
||||
anchor(tagName, attributes, children) {
|
||||
return new AnchorPoint(attributes)
|
||||
},
|
||||
|
||||
block(tagName, attributes, children) {
|
||||
return Block.create({
|
||||
...attributes,
|
||||
nodes: createChildren(children),
|
||||
})
|
||||
},
|
||||
|
||||
cursor(tagName, attributes, children) {
|
||||
return new CursorPoint()
|
||||
},
|
||||
|
||||
decoration(tagName, attributes, children) {
|
||||
const { key, data } = attributes
|
||||
const type = tagName
|
||||
|
||||
if (key) {
|
||||
return new DecorationPoint({ key, type, data })
|
||||
}
|
||||
|
||||
const nodes = createChildren(children)
|
||||
const node = nodes[0]
|
||||
const { __decorations = [] } = node
|
||||
const __decoration = {
|
||||
anchorOffset: 0,
|
||||
focusOffset: nodes.reduce((len, n) => len + n.text.length, 0),
|
||||
type,
|
||||
data,
|
||||
}
|
||||
|
||||
__decorations.push(__decoration)
|
||||
node.__decorations = __decorations
|
||||
return nodes
|
||||
},
|
||||
|
||||
document(tagName, attributes, children) {
|
||||
return Document.create({
|
||||
...attributes,
|
||||
nodes: createChildren(children),
|
||||
})
|
||||
},
|
||||
|
||||
focus(tagName, attributes, children) {
|
||||
return new FocusPoint(attributes)
|
||||
},
|
||||
|
||||
inline(tagName, attributes, children) {
|
||||
return Inline.create({
|
||||
...attributes,
|
||||
nodes: createChildren(children),
|
||||
})
|
||||
},
|
||||
|
||||
mark(tagName, attributes, children) {
|
||||
const marks = Mark.createSet([attributes])
|
||||
const nodes = createChildren(children, { marks })
|
||||
return nodes
|
||||
},
|
||||
|
||||
selection(tagName, attributes, children) {
|
||||
const anchor = children.find(c => c instanceof AnchorPoint)
|
||||
const focus = children.find(c => c instanceof FocusPoint)
|
||||
const { marks, focused } = attributes
|
||||
const selection = Selection.create({
|
||||
marks,
|
||||
isFocused: focused,
|
||||
anchor: anchor && {
|
||||
key: anchor.key,
|
||||
offset: anchor.offset,
|
||||
path: anchor.path,
|
||||
},
|
||||
focus: focus && {
|
||||
key: focus.key,
|
||||
offset: focus.offset,
|
||||
path: focus.path,
|
||||
},
|
||||
})
|
||||
|
||||
return selection
|
||||
},
|
||||
|
||||
text(tagName, attributes, children) {
|
||||
const nodes = createChildren(children, { key: attributes.key })
|
||||
return nodes
|
||||
},
|
||||
|
||||
value(tagName, attributes, children) {
|
||||
const { data, normalize = true } = attributes
|
||||
const document = children.find(Document.isDocument)
|
||||
let selection = children.find(Selection.isSelection) || Selection.create()
|
||||
let anchor
|
||||
let focus
|
||||
let decorations = []
|
||||
const partials = {}
|
||||
|
||||
// Search the document's texts to see if any of them have the anchor or
|
||||
// focus information saved, or decorations applied.
|
||||
if (document) {
|
||||
document.getTexts().forEach(text => {
|
||||
if (text.__anchor != null) {
|
||||
anchor = Point.create({ key: text.key, offset: text.__anchor.offset })
|
||||
}
|
||||
|
||||
if (text.__focus != null) {
|
||||
focus = Point.create({ key: text.key, offset: text.__focus.offset })
|
||||
}
|
||||
|
||||
if (text.__decorations != null) {
|
||||
text.__decorations.forEach(dec => {
|
||||
const { id } = dec
|
||||
let range
|
||||
|
||||
if (!id) {
|
||||
range = Decoration.create({
|
||||
anchor: {
|
||||
key: text.key,
|
||||
offset: dec.anchorOffset,
|
||||
},
|
||||
focus: {
|
||||
key: text.key,
|
||||
offset: dec.focusOffset,
|
||||
},
|
||||
mark: {
|
||||
type: dec.type,
|
||||
data: dec.data,
|
||||
},
|
||||
})
|
||||
} else if (partials[id]) {
|
||||
const partial = partials[id]
|
||||
delete partials[id]
|
||||
|
||||
range = Decoration.create({
|
||||
anchor: {
|
||||
key: partial.key,
|
||||
offset: partial.offset,
|
||||
},
|
||||
focus: {
|
||||
key: text.key,
|
||||
offset: dec.offset,
|
||||
},
|
||||
mark: {
|
||||
type: dec.type,
|
||||
data: dec.data,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
dec.key = text.key
|
||||
partials[id] = dec
|
||||
}
|
||||
|
||||
if (range) {
|
||||
decorations.push(range)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (Object.keys(partials).length > 0) {
|
||||
throw new Error(
|
||||
`Slate hyperscript must have both a start and an end defined for each decoration using the \`key=\` prop.`
|
||||
)
|
||||
}
|
||||
|
||||
if (anchor && !focus) {
|
||||
throw new Error(
|
||||
`Slate hyperscript ranges must have both \`<anchor />\` and \`<focus />\` defined if one is defined, but you only defined \`<anchor />\`. For collapsed selections, use \`<cursor />\` instead.`
|
||||
)
|
||||
}
|
||||
|
||||
if (!anchor && focus) {
|
||||
throw new Error(
|
||||
`Slate hyperscript ranges must have both \`<anchor />\` and \`<focus />\` defined if one is defined, but you only defined \`<focus />\`. For collapsed selections, use \`<cursor />\` instead.`
|
||||
)
|
||||
}
|
||||
|
||||
let value = Value.fromJSON(
|
||||
{ data, document, selection, ...attributes },
|
||||
{ normalize }
|
||||
)
|
||||
|
||||
if (anchor || focus) {
|
||||
selection = selection.setPoints([anchor, focus])
|
||||
selection = selection.setIsFocused(true)
|
||||
selection = selection.normalize(value.document)
|
||||
value = value.set('selection', selection)
|
||||
}
|
||||
|
||||
if (decorations.length > 0) {
|
||||
decorations = decorations.map(d => d.normalize(value.document))
|
||||
decorations = Decoration.createList(decorations)
|
||||
value = value.set('decorations', decorations)
|
||||
}
|
||||
|
||||
return value
|
||||
},
|
||||
}
|
||||
createAnchor,
|
||||
createBlock,
|
||||
createCursor,
|
||||
createDecoration,
|
||||
createDocument,
|
||||
createFocus,
|
||||
createInline,
|
||||
createMark,
|
||||
createNode,
|
||||
createSelection,
|
||||
createText,
|
||||
createValue,
|
||||
} from './creators'
|
||||
|
||||
/**
|
||||
* Create a Slate hyperscript function with `options`.
|
||||
@@ -290,7 +23,39 @@ const CREATORS = {
|
||||
*/
|
||||
|
||||
function createHyperscript(options = {}) {
|
||||
const creators = resolveCreators(options)
|
||||
const { blocks = {}, inlines = {}, marks = {}, decorations = {} } = options
|
||||
|
||||
const creators = {
|
||||
anchor: createAnchor,
|
||||
block: createBlock,
|
||||
cursor: createCursor,
|
||||
decoration: createDecoration,
|
||||
document: createDocument,
|
||||
focus: createFocus,
|
||||
inline: createInline,
|
||||
mark: createMark,
|
||||
node: createNode,
|
||||
selection: createSelection,
|
||||
text: createText,
|
||||
value: createValue,
|
||||
...(options.creators || {}),
|
||||
}
|
||||
|
||||
for (const key in blocks) {
|
||||
creators[key] = normalizeCreator(blocks[key], createBlock)
|
||||
}
|
||||
|
||||
for (const key in inlines) {
|
||||
creators[key] = normalizeCreator(inlines[key], createInline)
|
||||
}
|
||||
|
||||
for (const key in marks) {
|
||||
creators[key] = normalizeCreator(marks[key], createMark)
|
||||
}
|
||||
|
||||
for (const key in decorations) {
|
||||
creators[key] = normalizeCreator(decorations[key], createDecoration)
|
||||
}
|
||||
|
||||
function create(tagName, attributes, ...children) {
|
||||
const creator = creators[tagName]
|
||||
@@ -312,195 +77,22 @@ function createHyperscript(options = {}) {
|
||||
.filter(child => Boolean(child))
|
||||
.reduce((memo, child) => memo.concat(child), [])
|
||||
|
||||
const element = creator(tagName, attributes, children)
|
||||
return element
|
||||
const ret = creator(tagName, attributes, children)
|
||||
return ret
|
||||
}
|
||||
|
||||
return create
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an array of `children`, storing selection anchor and focus.
|
||||
*
|
||||
* @param {Array} children
|
||||
* @param {Object} options
|
||||
* @return {Array}
|
||||
*/
|
||||
|
||||
function createChildren(children, options = {}) {
|
||||
const array = []
|
||||
let length = 0
|
||||
|
||||
// When creating the new node, try to preserve a key if one exists.
|
||||
const firstNodeOrText = children.find(c => typeof c !== 'string')
|
||||
const firstText = Text.isText(firstNodeOrText) ? firstNodeOrText : null
|
||||
const key = options.key ? options.key : firstText ? firstText.key : undefined
|
||||
let node = Text.create({ key, leaves: [{ text: '', marks: options.marks }] })
|
||||
|
||||
// Create a helper to update the current node while preserving any stored
|
||||
// anchor or focus information.
|
||||
function setNode(next) {
|
||||
const { __anchor, __focus, __decorations } = node
|
||||
if (__anchor != null) next.__anchor = __anchor
|
||||
if (__focus != null) next.__focus = __focus
|
||||
if (__decorations != null) next.__decorations = __decorations
|
||||
node = next
|
||||
}
|
||||
|
||||
children.forEach((child, index) => {
|
||||
const isLast = index === children.length - 1
|
||||
|
||||
// If the child is a non-text node, push the current node and the new child
|
||||
// onto the array, then creating a new node for future selection tracking.
|
||||
if (Node.isNode(child) && !Text.isText(child)) {
|
||||
if (
|
||||
node.text.length ||
|
||||
node.__anchor != null ||
|
||||
node.__focus != null ||
|
||||
node.getMarksAtIndex(0).size
|
||||
) {
|
||||
array.push(node)
|
||||
}
|
||||
|
||||
array.push(child)
|
||||
|
||||
node = isLast
|
||||
? null
|
||||
: Text.create({ leaves: [{ text: '', marks: options.marks }] })
|
||||
|
||||
length = 0
|
||||
}
|
||||
|
||||
// If the child is a string insert it into the node.
|
||||
if (typeof child == 'string') {
|
||||
setNode(node.insertText(node.text.length, child, options.marks))
|
||||
length += child.length
|
||||
}
|
||||
|
||||
// If the node is a `Text` add its text and marks to the existing node. If
|
||||
// the existing node is empty, and the `key` option wasn't set, preserve the
|
||||
// child's key when updating the node.
|
||||
if (Text.isText(child)) {
|
||||
const { __anchor, __focus, __decorations } = child
|
||||
let i = node.text.length
|
||||
|
||||
if (!options.key && node.text.length == 0) {
|
||||
setNode(node.set('key', child.key))
|
||||
}
|
||||
|
||||
child.getLeaves().forEach(leaf => {
|
||||
let { marks } = leaf
|
||||
if (options.marks) marks = marks.union(options.marks)
|
||||
setNode(node.insertText(i, leaf.text, marks))
|
||||
i += leaf.text.length
|
||||
})
|
||||
|
||||
if (__anchor != null) {
|
||||
node.__anchor = new AnchorPoint()
|
||||
node.__anchor.offset = __anchor.offset + length
|
||||
}
|
||||
|
||||
if (__focus != null) {
|
||||
node.__focus = new FocusPoint()
|
||||
node.__focus.offset = __focus.offset + length
|
||||
}
|
||||
|
||||
if (__decorations != null) {
|
||||
__decorations.forEach(d => {
|
||||
if (d instanceof DecorationPoint) {
|
||||
d.offset += length
|
||||
} else {
|
||||
d.anchorOffset += length
|
||||
d.focusOffset += length
|
||||
}
|
||||
})
|
||||
|
||||
node.__decorations = node.__decorations || []
|
||||
node.__decorations = node.__decorations.concat(__decorations)
|
||||
}
|
||||
|
||||
length += child.text.length
|
||||
}
|
||||
|
||||
if (child instanceof AnchorPoint || child instanceof CursorPoint) {
|
||||
child.offset = length
|
||||
node.__anchor = child
|
||||
}
|
||||
|
||||
if (child instanceof FocusPoint || child instanceof CursorPoint) {
|
||||
child.offset = length
|
||||
node.__focus = child
|
||||
}
|
||||
|
||||
if (child instanceof DecorationPoint) {
|
||||
child.offset = length
|
||||
node.__decorations = node.__decorations || []
|
||||
node.__decorations = node.__decorations.concat(child)
|
||||
}
|
||||
})
|
||||
|
||||
// Make sure the most recent node is added.
|
||||
if (node != null) {
|
||||
array.push(node)
|
||||
}
|
||||
|
||||
return array
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a set of hyperscript creators an `options` object.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @return {Object}
|
||||
*/
|
||||
|
||||
function resolveCreators(options) {
|
||||
const {
|
||||
blocks = {},
|
||||
inlines = {},
|
||||
marks = {},
|
||||
decorations = {},
|
||||
schema,
|
||||
} = options
|
||||
|
||||
const creators = {
|
||||
...CREATORS,
|
||||
...(options.creators || {}),
|
||||
}
|
||||
|
||||
Object.keys(blocks).map(key => {
|
||||
creators[key] = normalizeNode(blocks[key], 'block')
|
||||
})
|
||||
|
||||
Object.keys(inlines).map(key => {
|
||||
creators[key] = normalizeNode(inlines[key], 'inline')
|
||||
})
|
||||
|
||||
Object.keys(marks).map(key => {
|
||||
creators[key] = normalizeMark(marks[key])
|
||||
})
|
||||
|
||||
Object.keys(decorations).map(key => {
|
||||
creators[key] = normalizeNode(decorations[key], 'decoration')
|
||||
})
|
||||
|
||||
creators.value = (tagName, attributes = {}, children) => {
|
||||
const attrs = { schema, ...attributes }
|
||||
return CREATORS.value(tagName, attrs, children)
|
||||
}
|
||||
|
||||
return creators
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a node creator of `value` and `object`.
|
||||
* Normalize a `creator` of `value`.
|
||||
*
|
||||
* @param {Function|Object|String} value
|
||||
* @param {String} object
|
||||
* @param {Function} creator
|
||||
* @return {Function}
|
||||
*/
|
||||
|
||||
function normalizeNode(value, object) {
|
||||
function normalizeCreator(value, creator) {
|
||||
if (typeof value == 'function') {
|
||||
return value
|
||||
}
|
||||
@@ -514,7 +106,6 @@ function normalizeNode(value, object) {
|
||||
const { key, ...rest } = attributes
|
||||
const attrs = {
|
||||
...value,
|
||||
object,
|
||||
key,
|
||||
data: {
|
||||
...(value.data || {}),
|
||||
@@ -522,47 +113,12 @@ function normalizeNode(value, object) {
|
||||
},
|
||||
}
|
||||
|
||||
return CREATORS[object](tagName, attrs, children)
|
||||
return creator(tagName, attrs, children)
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Slate hyperscript ${object} creators can be either functions, objects or strings, but you passed: ${value}`
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a mark creator of `value`.
|
||||
*
|
||||
* @param {Function|Object|String} value
|
||||
* @return {Function}
|
||||
*/
|
||||
|
||||
function normalizeMark(value) {
|
||||
if (typeof value == 'function') {
|
||||
return value
|
||||
}
|
||||
|
||||
if (typeof value == 'string') {
|
||||
value = { type: value }
|
||||
}
|
||||
|
||||
if (isPlainObject(value)) {
|
||||
return (tagName, attributes, children) => {
|
||||
const attrs = {
|
||||
...value,
|
||||
data: {
|
||||
...(value.data || {}),
|
||||
...attributes,
|
||||
},
|
||||
}
|
||||
|
||||
return CREATORS.mark(tagName, attrs, children)
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Slate hyperscript mark creators can be either functions, objects or strings, but you passed: ${value}`
|
||||
`Slate hyperscript creators can be either functions, objects or strings, but you passed: ${value}`
|
||||
)
|
||||
}
|
||||
|
||||
|
12
packages/slate-hyperscript/test/fixtures/block-empty.js
vendored
Normal file
12
packages/slate-hyperscript/test/fixtures/block-empty.js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = <block type="paragraph" />
|
||||
|
||||
export const output = {
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [],
|
||||
}
|
23
packages/slate-hyperscript/test/fixtures/block-inline-empty.js
vendored
Normal file
23
packages/slate-hyperscript/test/fixtures/block-inline-empty.js
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = (
|
||||
<block type="paragraph">
|
||||
<inline type="link" />
|
||||
</block>
|
||||
)
|
||||
|
||||
export const output = {
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'inline',
|
||||
type: 'link',
|
||||
data: {},
|
||||
nodes: [],
|
||||
},
|
||||
],
|
||||
}
|
@@ -3,18 +3,19 @@
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = (
|
||||
<document>
|
||||
<block type="paragraph">word</block>
|
||||
</document>
|
||||
<block type="paragraph">
|
||||
<inline type="link">word</inline>
|
||||
</block>
|
||||
)
|
||||
|
||||
export const output = {
|
||||
object: 'document',
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
object: 'inline',
|
||||
type: 'link',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
33
packages/slate-hyperscript/test/fixtures/block-mark-empty.js
vendored
Normal file
33
packages/slate-hyperscript/test/fixtures/block-mark-empty.js
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = (
|
||||
<block type="paragraph">
|
||||
<mark type="bold" />
|
||||
</block>
|
||||
)
|
||||
|
||||
export const output = {
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: '',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
33
packages/slate-hyperscript/test/fixtures/block-mark-full.js
vendored
Normal file
33
packages/slate-hyperscript/test/fixtures/block-mark-full.js
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = (
|
||||
<block type="paragraph">
|
||||
<mark type="bold">word</mark>
|
||||
</block>
|
||||
)
|
||||
|
||||
export const output = {
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'word',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
62
packages/slate-hyperscript/test/fixtures/block-mark-nested.js
vendored
Normal file
62
packages/slate-hyperscript/test/fixtures/block-mark-nested.js
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = (
|
||||
<block type="paragraph">
|
||||
<mark type="bold">
|
||||
w<mark type="italic">or</mark>d
|
||||
</mark>
|
||||
</block>
|
||||
)
|
||||
|
||||
export const output = {
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'w',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'or',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'italic',
|
||||
data: {},
|
||||
},
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'd',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
23
packages/slate-hyperscript/test/fixtures/block-string.js
vendored
Normal file
23
packages/slate-hyperscript/test/fixtures/block-string.js
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = <block type="paragraph">word</block>
|
||||
|
||||
export const output = {
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'word',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
27
packages/slate-hyperscript/test/fixtures/block-text-empty.js
vendored
Normal file
27
packages/slate-hyperscript/test/fixtures/block-text-empty.js
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = (
|
||||
<block type="paragraph">
|
||||
<text />
|
||||
</block>
|
||||
)
|
||||
|
||||
export const output = {
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
27
packages/slate-hyperscript/test/fixtures/block-text-full.js
vendored
Normal file
27
packages/slate-hyperscript/test/fixtures/block-text-full.js
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = (
|
||||
<block type="paragraph">
|
||||
<text>word</text>
|
||||
</block>
|
||||
)
|
||||
|
||||
export const output = {
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'word',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
@@ -21,7 +21,7 @@ export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
key: '3',
|
||||
key: '2',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
|
@@ -6,14 +6,18 @@ export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<block type="paragraph">
|
||||
<text />
|
||||
<inline type="link">
|
||||
on<anchor />e
|
||||
</inline>
|
||||
<text />
|
||||
</block>
|
||||
<block type="paragraph">
|
||||
<text />
|
||||
<inline type="link">
|
||||
t<focus />wo
|
||||
</inline>
|
||||
<text />
|
||||
</block>
|
||||
</document>
|
||||
</value>
|
||||
@@ -33,13 +37,13 @@ export const output = {
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
key: '3',
|
||||
key: '4',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
key: '13',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
@@ -50,13 +54,13 @@ export const output = {
|
||||
},
|
||||
{
|
||||
object: 'inline',
|
||||
key: '1',
|
||||
key: '2',
|
||||
type: 'link',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
key: '1',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
@@ -69,7 +73,7 @@ export const output = {
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
key: '14',
|
||||
key: '3',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
@@ -82,13 +86,13 @@ export const output = {
|
||||
},
|
||||
{
|
||||
object: 'block',
|
||||
key: '7',
|
||||
key: '9',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
key: '11',
|
||||
key: '5',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
@@ -99,13 +103,13 @@ export const output = {
|
||||
},
|
||||
{
|
||||
object: 'inline',
|
||||
key: '5',
|
||||
key: '7',
|
||||
type: 'link',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
key: '4',
|
||||
key: '6',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
@@ -118,7 +122,7 @@ export const output = {
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
key: '12',
|
||||
key: '8',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
@@ -135,13 +139,13 @@ export const output = {
|
||||
object: 'selection',
|
||||
anchor: {
|
||||
object: 'point',
|
||||
key: '0',
|
||||
key: '1',
|
||||
path: [0, 1, 0],
|
||||
offset: 2,
|
||||
},
|
||||
focus: {
|
||||
object: 'point',
|
||||
key: '4',
|
||||
key: '6',
|
||||
path: [1, 1, 0],
|
||||
offset: 1,
|
||||
},
|
||||
|
@@ -24,7 +24,7 @@ export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
key: '6',
|
||||
key: '4',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
|
@@ -24,7 +24,7 @@ export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
key: '6',
|
||||
key: '4',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
|
@@ -24,7 +24,7 @@ export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
key: '6',
|
||||
key: '4',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
|
@@ -25,7 +25,7 @@ export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
key: '9',
|
||||
key: '6',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
|
@@ -25,7 +25,7 @@ export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
key: '9',
|
||||
key: '6',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
|
@@ -25,7 +25,7 @@ export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
key: '9',
|
||||
key: '6',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
|
@@ -21,7 +21,7 @@ export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
key: '3',
|
||||
key: '2',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
|
@@ -21,7 +21,7 @@ export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
key: '3',
|
||||
key: '2',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
|
@@ -21,7 +21,7 @@ export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
key: '3',
|
||||
key: '2',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
|
@@ -27,7 +27,7 @@ export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
key: '3',
|
||||
key: '2',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
|
@@ -26,7 +26,7 @@ export const output = {
|
||||
document: {
|
||||
object: 'document',
|
||||
data: {},
|
||||
key: '6',
|
||||
key: '5',
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
|
@@ -26,7 +26,7 @@ export const output = {
|
||||
document: {
|
||||
object: 'document',
|
||||
data: {},
|
||||
key: '6',
|
||||
key: '5',
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
|
@@ -26,7 +26,7 @@ export const output = {
|
||||
document: {
|
||||
object: 'document',
|
||||
data: {},
|
||||
key: '6',
|
||||
key: '5',
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
|
@@ -26,7 +26,7 @@ export const output = {
|
||||
document: {
|
||||
object: 'document',
|
||||
data: {},
|
||||
key: '3',
|
||||
key: '2',
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
|
@@ -26,7 +26,7 @@ export const output = {
|
||||
document: {
|
||||
object: 'document',
|
||||
data: {},
|
||||
key: '3',
|
||||
key: '2',
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
|
@@ -26,7 +26,7 @@ export const output = {
|
||||
document: {
|
||||
object: 'document',
|
||||
data: {},
|
||||
key: '3',
|
||||
key: '2',
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
|
@@ -101,18 +101,7 @@ export const output = {
|
||||
data: {
|
||||
src: 'https://...',
|
||||
},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
nodes: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -30,7 +30,7 @@ export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
key: '3',
|
||||
key: '2',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
@@ -33,7 +33,7 @@ export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
key: '6',
|
||||
key: '4',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
11
packages/slate-hyperscript/test/fixtures/document-empty.js
vendored
Normal file
11
packages/slate-hyperscript/test/fixtures/document-empty.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = <document />
|
||||
|
||||
export const output = {
|
||||
object: 'document',
|
||||
data: {},
|
||||
nodes: [],
|
||||
}
|
12
packages/slate-hyperscript/test/fixtures/inline-empty.js
vendored
Normal file
12
packages/slate-hyperscript/test/fixtures/inline-empty.js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = <inline type="link" />
|
||||
|
||||
export const output = {
|
||||
object: 'inline',
|
||||
type: 'link',
|
||||
data: {},
|
||||
nodes: [],
|
||||
}
|
23
packages/slate-hyperscript/test/fixtures/inline-full.js
vendored
Normal file
23
packages/slate-hyperscript/test/fixtures/inline-full.js
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = <inline type="link">word</inline>
|
||||
|
||||
export const output = {
|
||||
object: 'inline',
|
||||
type: 'link',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'word',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
@@ -1,41 +0,0 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = (
|
||||
<document>
|
||||
<block type="paragraph">
|
||||
<mark type="bold" />
|
||||
</block>
|
||||
</document>
|
||||
)
|
||||
|
||||
export const output = {
|
||||
object: 'document',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: '',
|
||||
marks: [
|
||||
{
|
||||
type: 'bold',
|
||||
object: 'mark',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
@@ -1,39 +0,0 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<block type="paragraph">word</block>
|
||||
<text>invalid</text>
|
||||
</document>
|
||||
</value>
|
||||
)
|
||||
|
||||
export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'word',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = (
|
||||
<value normalize={false}>
|
||||
<document>
|
||||
<block type="paragraph">word</block>
|
||||
<text>invalid</text>
|
||||
</document>
|
||||
</value>
|
||||
)
|
||||
|
||||
export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'word',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'invalid',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
@@ -6,7 +6,7 @@ export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<block type="paragraph">
|
||||
one<text key="a">two</text>three
|
||||
<text key="a">two</text>
|
||||
</block>
|
||||
</document>
|
||||
<selection>
|
||||
@@ -25,7 +25,7 @@ export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
key: '2',
|
||||
key: '1',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
@@ -40,7 +40,7 @@ export const output = {
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'onetwothree',
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
|
16
packages/slate-hyperscript/test/fixtures/text-empty.js
vendored
Normal file
16
packages/slate-hyperscript/test/fixtures/text-empty.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = <text />
|
||||
|
||||
export const output = {
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
}
|
16
packages/slate-hyperscript/test/fixtures/text-full.js
vendored
Normal file
16
packages/slate-hyperscript/test/fixtures/text-full.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = <text>word</text>
|
||||
|
||||
export const output = {
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'word',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
}
|
@@ -1,73 +0,0 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = (
|
||||
<document>
|
||||
<block type="paragraph">
|
||||
Cat <inline type="link">is</inline>
|
||||
<text key="a"> cute</text>
|
||||
</block>
|
||||
</document>
|
||||
)
|
||||
|
||||
export const options = {
|
||||
preserveKeys: true,
|
||||
}
|
||||
|
||||
export const output = {
|
||||
object: 'document',
|
||||
key: '6',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
key: '4',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
key: '2',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'Cat ',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'inline',
|
||||
key: '1',
|
||||
type: 'link',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'is',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
key: 'a',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: ' cute',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
21
packages/slate-hyperscript/test/fixtures/text-with-key.js
vendored
Normal file
21
packages/slate-hyperscript/test/fixtures/text-with-key.js
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = <text key="a">word</text>
|
||||
|
||||
export const options = {
|
||||
preserveKeys: true,
|
||||
}
|
||||
|
||||
export const output = {
|
||||
object: 'text',
|
||||
key: 'a',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'word',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
}
|
@@ -1,109 +0,0 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<block type="paragraph">
|
||||
A string of <mark type="bold">bold</mark> in a{' '}
|
||||
<inline type="link" data={{ src: 'http://slatejs.org' }}>
|
||||
Slate
|
||||
</inline>{' '}
|
||||
editor!
|
||||
</block>
|
||||
<block type="image" data={{ src: 'https://...' }} />
|
||||
</document>
|
||||
</value>
|
||||
)
|
||||
|
||||
export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'A string of ',
|
||||
marks: [],
|
||||
},
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'bold',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'leaf',
|
||||
text: ' in a ',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'inline',
|
||||
type: 'link',
|
||||
data: {
|
||||
src: 'http://slatejs.org',
|
||||
},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'Slate',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: ' editor!',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'block',
|
||||
type: 'image',
|
||||
data: {
|
||||
src: 'https://...',
|
||||
},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
Reference in New Issue
Block a user