React CS Editor

Showing how to build HTML dynamically

by Ben Clayton

HTML

<div id="app"></div>

CSS

body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app,
#app2 {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

.cols {
  display: inline-block;
  width: 40%;
}
.row {
	margin-bottom:10px;
}

li {
  margin: 8px 0;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

.done {
  color: rgba(0, 0, 0, 0.3);
  text-decoration: line-through;
}

input {
  margin-right: 5px;
}
.editview{
	border:1px solid gray;
	padding:10px;
	min-height:500px;
}
.clearboth {
	clear:both;
}

React

//  https://zhenyong.github.io/react/docs/more-about-refs.html

var blocks = []
class Base extends React.Component {
  constructor(props) {
    super(props)
		if(props.rawdata){
			var data=props.rawdata();
			if (data.content){
				var idx = props.idx;
				if (data.content.length){
					this.state = {content:[]}
					var key=0
					data.content.forEach((blk)=>{
						this.state.content.push({content:factory(idx+'-'+key,blk.type,blk),key:key++})
					})
				} else {
					var blk = this.data
					this.state.content = factory(idx+'-0',blk.type,blk.content)
				}
			}
			console.log("rawdata",data)
			blocks[props.idx]=this
			if(this.premount){
				this.premount(data)
			}
		}	
  }
}


function factory(idx,type,data){
		switch (type){
				case "Body":
				return <BodyEditor idx={idx} rawdata={(ref) =>{return data}} />	
				case "Heading":
				return <HeadingEditor idx={idx} rawdata={(ref) =>{return data}} />	
				case "SubHeading":
				return <SubHeadingEditor idx={idx} rawdata={(ref) =>{return data}} />
				case "MultiColFrame":
				return <MultiColFrame idx={idx} rawdata={(ref) =>{return data}} />
				case "MultiColColumn":
				return <MultiColColumn idx={idx} rawdata={(ref) =>{return data}} />
				case "Picture":
				return <Picture idx={idx} rawdata={(ref) =>{return data}} />
				default:
				console.error("type not recognised ",type)
		}
		return null
}

class MultiColFrame extends Base {
	  
  render() {
    return (
				<div>
       		{
					this.state.content.map(col => (
						<div key={col.key} className='cols'>{col.content}</div>
			  	))
					}
					<div className="clearboth"></div>
			</div>
			
     )
  }
}

class MultiColColumn extends Base {
	  
  render() {
    return (
				<div>
       {this.state.content.map(row => (
					<div key={row.key} className='row'>{row.content}</div>
			  ))}
				</div>
     )
  }
}

class Body extends Base {
	premount(data){
		this.state={text: data.text};
	}
   render() {
    return (
      <i>
       ...