diff --git a/examples/auto-markdown/index.js b/examples/auto-markdown/index.js
index 789a36943..b060b43f4 100644
--- a/examples/auto-markdown/index.js
+++ b/examples/auto-markdown/index.js
@@ -63,7 +63,7 @@ class App extends React.Component {
return (props) =>
{props.children}
}
case 'bulleted-list': {
- return (props) =>
+ return (props) =>
}
case 'heading-one': {
return (props) => {props.children}
@@ -84,10 +84,7 @@ class App extends React.Component {
return (props) => {props.children}
}
case 'list-item': {
- return (props) => {props.chidlren}
- }
- case 'numbered-list': {
- return (props) => {props.children}
+ return (props) => {props.children}
}
case 'paragraph': {
return (props) => {props.children}
@@ -153,24 +150,28 @@ class App extends React.Component {
case '>':
transform = transform.setType('block-quote')
break
+ case '*':
case '-':
- transform = transform.setType('list-item')
- const wrapper = document.getParentNode(node)
- if (wrapper.type == 'paragraph') transform = transform.setType('bulleted-list')
- if (wrapper.type == 'bulleted-list') transform = transform.wrap('list-item')
- if (wrapper.type == 'list-item') transform = transform.wrap('unordered-list')
+ case '+':
+ if (node.type == 'list-item') break
+ transform = node.type == 'list-item'
+ ? transform
+ : transform
+ .setType('list-item')
+ .wrap('bulleted-list')
break
default:
return
}
+ e.preventDefault()
+
state = transform
.deleteAtRange(selection.extendBackwardToStartOf(node))
.apply()
selection = selection.moveToStartOf(node)
state = state.merge({ selection })
- e.preventDefault()
return state
}
@@ -189,12 +190,16 @@ class App extends React.Component {
const node = state.currentBlockNodes.first()
if (!node) debugger
if (node.type == 'paragraph') return
-
e.preventDefault()
- return state
+
+ let transform = state
.transform()
.setType('paragraph')
- .apply()
+
+ if (node.type == 'list-item') transform = transform.unwrap('bulleted-list')
+
+ state = transform.apply()
+ return state
}
/**
diff --git a/lib/components/content.js b/lib/components/content.js
index b8e3a04d7..1a4cd8aae 100644
--- a/lib/components/content.js
+++ b/lib/components/content.js
@@ -145,7 +145,6 @@ class Content extends React.Component {
*/
render() {
- console.log('Rendered content.')
const { state } = this.props
const { document } = state
const children = document.nodes
@@ -175,39 +174,65 @@ class Content extends React.Component {
}
/**
- * Render a single `node`.
+ * Render a `node`.
*
* @param {Node} node
* @return {Component} component
*/
renderNode(node) {
- const { renderMark, renderNode, state } = this.props
-
- if (node instanceof TextModel) {
- return (
-
- )
+ switch (node.kind) {
+ case 'text':
+ return this.renderText(node)
+ case 'block':
+ case 'inline':
+ return this.renderElement(node)
}
+ }
+ /**
+ * Render a text `node`.
+ *
+ * @param {Node} node
+ * @return {Component} component
+ */
+
+ renderText(node) {
+ const { renderMark, renderNode, state } = this.props
+ return (
+
+ )
+ }
+
+ /**
+ * Render an element `node`.
+ *
+ * @param {Node} node
+ * @return {Component} component
+ */
+
+ renderElement(node) {
+ const { renderNode, state } = this.props
const Component = renderNode(node)
const children = node.nodes
- .map(node => this.renderNode(node))
+ .map(child => this.renderNode(child))
.toArray()
return (
+ >
+ {children}
+
)
+
}
}
diff --git a/lib/models/block.js b/lib/models/block.js
index 7dc547bd5..4c797758b 100644
--- a/lib/models/block.js
+++ b/lib/models/block.js
@@ -1,7 +1,7 @@
import Node from './node'
import uid from 'uid'
-import { OrderedMap, Record } from 'immutable'
+import { Map, OrderedMap, Record } from 'immutable'
/**
* Default properties.
diff --git a/lib/models/document.js b/lib/models/document.js
index 0dce6574b..6e20b2407 100644
--- a/lib/models/document.js
+++ b/lib/models/document.js
@@ -7,8 +7,7 @@ import { OrderedMap, Record } from 'immutable'
*/
const DEFAULTS = {
- nodes: new OrderedMap(),
- parent: null
+ nodes: new OrderedMap()
}
/**
diff --git a/lib/models/inline.js b/lib/models/inline.js
index 5da17958c..20aafafd1 100644
--- a/lib/models/inline.js
+++ b/lib/models/inline.js
@@ -1,7 +1,7 @@
import Node from './node'
import uid from 'uid'
-import { OrderedMap, Record } from 'immutable'
+import { Map, OrderedMap, Record } from 'immutable'
/**
* Record.
diff --git a/lib/models/node.js b/lib/models/node.js
index 31c52f547..5828efbde 100644
--- a/lib/models/node.js
+++ b/lib/models/node.js
@@ -886,32 +886,42 @@ const Node = {
},
/**
- * Wrap all of the nodes in a `range` in a new `parent` node.
+ * Wrap all of the nodes in a `range` in a new parent node of `type`.
*
* @param {Selection} range
- * @param {Node or String} parent
+ * @param {String} type
* @return {Node} node
*/
- wrapAtRange(range, parent) {
+ wrapAtRange(range, type) {
+ range = range.normalize(this)
let node = this
- range = range.normalize(node)
+ let blocks = node.getBlockNodesAtRange(range)
- // Allow for the parent to by just a type.
- if (typeof parent == 'string') {
- parent = Block.create({ type: parent })
- }
+ // Iterate each of the block nodes, wrapping them.
+ blocks.forEach((block) => {
+ let isDirectChild = node.nodes.has(block.key)
+ let parent = isDirectChild ? node : node.getParentNode(block)
- // Add the child to the parent's nodes.
- const child = node.findNode(key)
- parent = node.nodes.set(child.key, child)
+ // Create a new wrapper containing the block.
+ let nodes = Block.createMap([ block ])
+ let wrapper = Block.create({ type, nodes })
- // Remove the child from this node.
- node = node.removeNode(child)
+ // Replace the block in it's parent with the wrapper.
+ nodes = parent.nodes.takeUntil(node => node == block)
+ .set(wrapper.key, wrapper)
+ .concat(parent.nodes.skipUntil(node => node == block).rest())
- // Add the parent to this node.
+ // Update the parent.
+ if (isDirectChild) {
+ node = node.merge({ nodes })
+ } else {
+ parent = parent.merge({ nodes })
+ node = node.updateNode(parent)
+ }
+ })
- return node
+ return node.normalize()
}
/**
diff --git a/lib/models/state.js b/lib/models/state.js
index 173a7ed4d..c30ed3549 100644
--- a/lib/models/state.js
+++ b/lib/models/state.js
@@ -338,6 +338,21 @@ class State extends Record(DEFAULTS) {
return state
}
+ /**
+ * Wrap the block nodes in the current selection in new nodes of `type`.
+ *
+ * @param {String} type
+ * @return {State} state
+ */
+
+ wrap(type) {
+ let state = this
+ let { document, selection } = state
+ document = document.wrapAtRange(selection, type)
+ state = state.merge({ document })
+ return state
+ }
+
}
/**
diff --git a/lib/models/text.js b/lib/models/text.js
index 81f22d2fc..75811c48b 100644
--- a/lib/models/text.js
+++ b/lib/models/text.js
@@ -8,8 +8,7 @@ import { List, Record } from 'immutable'
const DEFAULTS = {
characters: new List(),
- key: null,
- parent: null
+ key: null
}
/**
diff --git a/lib/models/transform.js b/lib/models/transform.js
index 906984a68..9b3582625 100644
--- a/lib/models/transform.js
+++ b/lib/models/transform.js
@@ -51,7 +51,11 @@ const TRANSFORM_TYPES = [
'split',
'splitAtRange',
'unmark',
- 'unmarkAtRange'
+ 'unmarkAtRange',
+ 'unwrap',
+ 'unwrapAtRange',
+ 'wrap',
+ 'wrapAtRange'
]
/**