diff --git a/examples/iframe-rendering/Readme.md b/examples/iframe-rendering/Readme.md
index bc30e1aaf..a4756b524 100644
--- a/examples/iframe-rendering/Readme.md
+++ b/examples/iframe-rendering/Readme.md
@@ -1,7 +1,14 @@
-
# IFrame rendering example
This example shows how to render Slate into IFrame, preserving single react component tree.
You may need this if you want to have separate styles for editor content & application.
+In example this exmaple you can see,
+that editor is using bootstrap styles, while they are not included to parent page.
+
+## React onSelect problem
+Current react version has a problem with onSelect event handling, if input is rendered from parent component tree to iframe.
+
+This problem is solved by custom SelectEventPlugin - [react-frame-aware-selection-plugin](https://www.npmjs.com/package/react-frame-aware-selection-plugin)
+
Check out the [Examples readme](..) to see how to run it!
diff --git a/examples/iframe-rendering/index.js b/examples/iframe-rendering/index.js
index d55676233..708df9956 100644
--- a/examples/iframe-rendering/index.js
+++ b/examples/iframe-rendering/index.js
@@ -1,77 +1,129 @@
import React from 'react'
import ReactDOM from 'react-dom'
-function resolveDocument (reactIFrameElementNode) {
- const iFrame = ReactDOM.findDOMNode(reactIFrameElementNode);
- return iFrame.contentDocument
+import injector from 'react-frame-aware-selection-plugin'
+injector();
+
+import { Editor, Mark, Raw } from '../..'
+import initialState from './state.json'
+import Frame from 'react-frame-component'
+
+const MARKS = {
+ bold: {
+ fontWeight: 'bold'
+ },
+ italic: {
+ fontStyle: 'italic'
+ }
}
-//appending context to body > div, to suppress react warning
-function getRootDiv (doc) {
- let rootDiv = doc.querySelector('div#root')
- if (!rootDiv) {
- rootDiv = doc.createElement('div')
- rootDiv.setAttribute('id', 'root')
- rootDiv.id = 'root'
- rootDiv.setAttribute('style', 'width: 100%; height: 100%')
-
- doc.body.appendChild(rootDiv)
- }
- return rootDiv
-}
-
-class IFrame extends React.Component {
-
- static propTypes = {
- head: React.PropTypes.node,
- children: React.PropTypes.node,
- }
-
- //rendering plain frame.
- render () {
- return
- }
-
- componentDidMount = () => {
- this.renderContents()
- }
-
- componentDidUpdate = () => {
- this.renderContents()
- }
-
- componentWillUnmount = () => this.getDocument().then((doc) => {
- ReactDOM.unmountComponentAtNode(doc.body)
- if (this.props.head) {
- ReactDOM.unmountComponentAtNode(doc.head)
- }
- })
-
- renderContents = () => this.getDocument().then((doc) => {
- if (this.props.head) {
- ReactDOM.unstable_renderSubtreeIntoContainer(this, this.props.head, doc.head)
- }
- const rootDiv = getRootDiv(doc)
- ReactDOM.unstable_renderSubtreeIntoContainer(this, this.props.children, rootDiv)
- })
-
-
- getDocument = () => new Promise((resolve) => {
- const resolveTick = () => { //using arrow function to preserve `this` context
- let doc = resolveDocument(this)
- if (doc && doc.readyState === 'complete') {
- resolve(doc)
- } else {
- window.requestAnimationFrame(resolveTick)
- }
- }
- resolveTick()
- })
-
+const NODES = {
+ 'table': props =>
,
+ 'table-row': props => {props.children}
,
+ 'table-cell': props => {props.children} |
}
class IFrameRendering extends React.Component {
+ state = {
+ state: Raw.deserialize(initialState, { terse: true })
+ };
+
+ onChange = (state) => {
+ this.setState({ state })
+ }
+
+ /**
+ * On backspace, do nothing if at the start of a table cell.
+ *
+ * @param {Event} e
+ * @param {State} state
+ * @return {State or Null} state
+ */
+
+ onBackspace = (e, state) => {
+ if (state.startOffset != 0) return
+ e.preventDefault()
+ return state
+ }
+
+ /**
+ * On change.
+ *
+ * @param {State} state
+ */
+
+ onChange = (state) => {
+ this.setState({ state })
+ }
+
+ /**
+ * On delete, do nothing if at the end of a table cell.
+ *
+ * @param {Event} e
+ * @param {State} state
+ * @return {State or Null} state
+ */
+
+ onDelete = (e, state) => {
+ if (state.endOffset != state.startText.length) return
+ e.preventDefault()
+ return state
+ }
+
+ /**
+ * On return, do nothing if inside a table cell.
+ *
+ * @param {Event} e
+ * @param {State} state
+ * @return {State or Null} state
+ */
+
+ onEnter = (e, state) => {
+ e.preventDefault()
+ return state
+ }
+
+ /**
+ * On key down, check for our specific key shortcuts.
+ *
+ * @param {Event} e
+ * @param {Object} data
+ * @param {State} state
+ * @return {State or Null} state
+ */
+
+ onKeyDown = (e, data, state) => {
+ if (state.startBlock.type != 'table-cell') return
+ switch (data.key) {
+ case 'backspace': return this.onBackspace(e, state)
+ case 'delete': return this.onDelete(e, state)
+ case 'enter': return this.onEnter(e, state)
+ }
+ }
+
+ /**
+ * Return a node renderer for a Slate `node`.
+ *
+ * @param {Node} node
+ * @return {Component or Void}
+ */
+
+ renderNode = (node) => {
+ return NODES[node.type]
+ }
+
+ /**
+ * Return a mark renderer for a Slate `mark`.
+ *
+ * @param {Mark} mark
+ * @return {Object or Void}
+ */
+
+ renderMark = (mark) => {
+ return MARKS[mark.type]
+ }
+
render () {
const bootstrapCDN =
return (
-
+
+
+
)
}
diff --git a/examples/iframe-rendering/state.json b/examples/iframe-rendering/state.json
new file mode 100644
index 000000000..d8809df13
--- /dev/null
+++ b/examples/iframe-rendering/state.json
@@ -0,0 +1,277 @@
+{
+ "nodes": [
+ {
+ "kind": "block",
+ "type": "paragraph",
+ "nodes": [
+ {
+ "kind": "text",
+ "ranges": [
+ {
+ "text": "This example shows how you can render editor in frame component."
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "block",
+ "type": "paragraph",
+ "nodes": [
+ {
+ "kind": "text",
+ "ranges": [
+ {
+ "text": "Check out this table, it has bootstrap styles, and top level document is not polluted by "
+ },
+ {
+ "text": "bootstrap.min.css",
+ "marks": [
+ {
+ "type": "italic"
+ },
+ {
+ "type": "bold"
+ }
+ ]
+ },
+ {
+ "text": "."
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "block",
+ "type": "paragraph",
+ "nodes": [
+ {
+ "kind": "text",
+ "ranges": [
+ {
+ "text": ""
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "block",
+ "type": "table",
+ "nodes": [
+ {
+ "kind": "block",
+ "type": "table-row",
+ "nodes": [
+ {
+ "kind": "block",
+ "type": "table-cell",
+ "nodes": [
+ {
+ "kind": "text",
+ "ranges": [
+ {
+ "text": ""
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "block",
+ "type": "table-cell",
+ "nodes": [
+ {
+ "kind": "text",
+ "ranges": [
+ {
+ "text": "Human",
+ "marks": [
+ {
+ "type": "bold"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "block",
+ "type": "table-cell",
+ "nodes": [
+ {
+ "kind": "text",
+ "ranges": [
+ {
+ "text": "Dog",
+ "marks": [
+ {
+ "type": "bold"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "block",
+ "type": "table-cell",
+ "nodes": [
+ {
+ "kind": "text",
+ "ranges": [
+ {
+ "text": "Cat",
+ "marks": [
+ {
+ "type": "bold"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "block",
+ "type": "table-row",
+ "nodes": [
+ {
+ "kind": "block",
+ "type": "table-cell",
+ "nodes": [
+ {
+ "kind": "text",
+ "ranges": [
+ {
+ "text": "# of Feet",
+ "marks": [
+ {
+ "type": "bold"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "block",
+ "type": "table-cell",
+ "nodes": [
+ {
+ "kind": "text",
+ "ranges": [
+ {
+ "text": "1"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "block",
+ "type": "table-cell",
+ "nodes": [
+ {
+ "kind": "text",
+ "ranges": [
+ {
+ "text": "4"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "block",
+ "type": "table-cell",
+ "nodes": [
+ {
+ "kind": "text",
+ "ranges": [
+ {
+ "text": "4"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "block",
+ "type": "table-row",
+ "nodes": [
+ {
+ "kind": "block",
+ "type": "table-cell",
+ "nodes": [
+ {
+ "kind": "text",
+ "ranges": [
+ {
+ "text": "# of Lives",
+ "marks": [
+ {
+ "type": "bold"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "block",
+ "type": "table-cell",
+ "nodes": [
+ {
+ "kind": "text",
+ "ranges": [
+ {
+ "text": "1"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "block",
+ "type": "table-cell",
+ "nodes": [
+ {
+ "kind": "text",
+ "ranges": [
+ {
+ "text": "1"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "block",
+ "type": "table-cell",
+ "nodes": [
+ {
+ "kind": "text",
+ "ranges": [
+ {
+ "text": "9"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/package.json b/package.json
index c2763bef9..3ebd09af4 100644
--- a/package.json
+++ b/package.json
@@ -48,6 +48,8 @@
"react": "^15.2.0",
"react-addons-perf": "^15.2.1",
"react-dom": "^15.1.0",
+ "react-frame-aware-selection-plugin": "0.0.1",
+ "react-frame-component": "^0.6.2",
"react-router": "^2.5.1",
"read-metadata": "^1.0.0",
"selection-position": "^1.0.0",