diff --git a/examples/iframe-rendering/Readme.md b/examples/iframe-rendering/Readme.md new file mode 100644 index 000000000..bc30e1aaf --- /dev/null +++ b/examples/iframe-rendering/Readme.md @@ -0,0 +1,7 @@ + +# 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. + +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 new file mode 100644 index 000000000..d55676233 --- /dev/null +++ b/examples/iframe-rendering/index.js @@ -0,0 +1,93 @@ +import React from 'react' +import ReactDOM from 'react-dom' + +function resolveDocument (reactIFrameElementNode) { + const iFrame = ReactDOM.findDOMNode(reactIFrameElementNode); + return iFrame.contentDocument +} + +//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() + }) + +} + +class IFrameRendering extends React.Component { + + render () { + const bootstrapCDN = + + + + return ( + + ) + } + +} + +export default IFrameRendering diff --git a/examples/index.js b/examples/index.js index d894e8666..f1565354e 100644 --- a/examples/index.js +++ b/examples/index.js @@ -22,6 +22,7 @@ import RTL from './rtl' import Tables from './tables' import DevPerformancePlain from './development/performance-plain' import DevPerformanceRich from './development/performance-rich' +import IFrameRendering from './iframe-rendering' /** * Perf. @@ -76,6 +77,7 @@ class App extends React.Component { {this.renderTab('Read-only', 'read-only')} {this.renderTab('RTL', 'rtl')} {this.renderTab('Plugins', 'plugins')} + {this.renderTab('IFrame', 'iframe')} ) } @@ -134,6 +136,7 @@ const router = ( + )