Skip to content

Instantly share code, notes, and snippets.

@mathieudutour
Created July 25, 2016 14:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mathieudutour/589bfa64f8daa64e91528b587adc4c6b to your computer and use it in GitHub Desktop.
Save mathieudutour/589bfa64f8daa64e91528b587adc4c6b to your computer and use it in GitHub Desktop.
import React from 'react'
import Portal from 'react-portal'
import { connect } from 'react-redux'
import Visualiser from './visualiser/Visualiser'
import { setExecutionMode, executeCodeBlock } from '../actions'
import { codeSelector } from '../selectors'
class CodeBlock extends React.Component {
constructor (props) {
super(props)
this.state = {
menu: null,
resultPortal: null
}
}
componentDidMount = () => {
this.updatePortals()
}
componentDidUpdate = () => {
this.updatePortals()
}
render () {
const { attributes, children, running, result, node } = this.props
return (
<pre ref='code'>
<code {...attributes}>
{children}
</code>
<Portal isOpened onOpen={this.onOpen}>
<div>
{this.renderButton('plain')}
{this.renderButton('interactive')}
{this.renderButton('autorun')}
<button onClick={() => this.props.dispatch(executeCodeBlock(node))}>
run
</button>
</div>
</Portal>
<Portal isOpened={running || result} onOpen={this.onOpenResult}>
<div className='resultContainer'>
<div hidden={!running} className='resultBlock'>
loading...
</div>
<div hidden={running || !result} className='graphBlock' id={'kayero-graph-' + node.key} />
<div hidden={running || !result} className='resultBlock'>
<Visualiser data={result} useHljs='true' updateContainer={this.updatePortals} />
</div>
</div>
</Portal>
</pre>
)
}
renderButton = (executionMode) => {
const { node } = this.props
const onClick = (e) => {
e.preventDefault()
return this.props.dispatch(setExecutionMode(node, executionMode))
}
return (
<button onClick={onClick}>
<span className='fa '>{executionMode}</span>
</button>
)
}
onOpen = (portal) => {
this.setState({ menu: portal.firstChild })
}
onOpenResult = (portal) => {
this.setState({ resultPortal: portal.firstChild })
}
updatePortals = () => {
const { menu, resultPortal } = this.state
if (menu) {
const { code } = this.refs
const rect = code.getBoundingClientRect()
menu.style.position = 'absolute'
menu.style.opacity = 1
menu.style.top = `${rect.top + window.scrollY - menu.offsetHeight}px`
menu.style.left = `${rect.left + window.scrollX - menu.offsetWidth / 2 + rect.width}px`
}
if (resultPortal) {
const { code } = this.refs
code.style.paddingBottom = (resultPortal.offsetHeight + 20) + 'px'
const rect = code.getBoundingClientRect()
resultPortal.style.position = 'absolute'
resultPortal.style.opacity = 1
resultPortal.style.top = `${rect.bottom + window.scrollY - resultPortal.offsetHeight}px`
resultPortal.style.left = `${rect.left + window.scrollX}px`
resultPortal.style.width = `${rect.width}px`
}
}
}
CodeBlock.propTypes = {
attributes: React.PropTypes.object.isRequired,
children: React.PropTypes.any.isRequired,
node: React.PropTypes.object.isRequired,
dispatch: React.PropTypes.func,
running: React.PropTypes.bool,
result: React.PropTypes.any
}
export default connect(codeSelector)(CodeBlock)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment