preact-markup demo

by Arif Hasan

HTML

<script src="https://npmcdn.com/preact@latest"></script>
<script src="https://npmcdn.com/preact-markup@latest"></script>
<script src="https://unpkg.com/linkstate/dist/polyfill.umd.js"></script>

SCSS

.placeholder-component {
	position: relative;
	display: inline-block;
	min-width: 200px;
	min-height: 140px;
	padding: 15px 5px;
	background: #EEE;
	border: 1px solid #CCC;
	border-radius: 3px;
	color: #999;
	text-align: center;
	& > h4 {
		position: absolute;
		left: 5px;
		top: 5px;
		margin: 0;
	}
	& > button {
		position: absolute;
		right: 5px;
		top: 5px;
		opacity: 0.5;
	}
	& > pre {
		text-align: left;
		font-size: 11px;
	}
	& > .inner {
		padding: 5px;
		text-align: left;
		background: #F4F4F4;
	}
}


aside.sidebar {
	display: block;
	float: right;
	width: 200px;
	min-height: 100%;
	background: #DDD;
	margin: 0 0 0 10px;
	padding: 10px;
}

header.toolbar {
	position: absolute;
	left: 0;
	top: 0;
	width: 100%;
	height: 56px;
	background: #acd;
	color: white;
	h1 { margin: 0; padding:10px; font-weight:300; }
	& ~ * {
		margin-top: 56px;
	}
}


* {
	position: relative;
	overflow: hidden;
	box-sizing: border-box;
}
li { overflow:visible; }

html,body,#app {
	position: absolute;
	left: 0;
	top: 0;
	width: 100%;
	height: 100%;
	margin: 0;
	padding: 0;
	font: 14px/1.21 'Helvetica Neue',arial,helvetica,sans-serif;
}

.toolbar {
	height: 40px;
	background: #EEE;
	border-bottom: 1px solid #DDD;
	button {
		margin: 4px;
		padding: 8px;
		background: #E4E4E4;
		border: 1px solid #CCC;
		color: #555;
		font-weight: bold;
		border-radius: 3px;
		cursor: pointer;
		outline: none;
		&:hover, &:active { background:#FFF; }
	}
}

.editor {
	position: absolute;
	left: 0;
	top: 0;
	height: 100%;
	width: 50%;
	border-right: 1px solid #BBB;

	textarea {
		position: absolute;
		left: 0;
		top: 40px;
		width: 100%;
		bottom: 0;
		padding: 10px;
		border: none;
		background: #FFF;
		font: 14px/1.21 'Source Code Pro', menlo, monaco, courier, monospace;
		resize: none;
		outline: none;
		overflow: auto;
	}
}

.preview {
	position: absolute;
	left: 50%;
	top: 0;
	width: 50%;
	height: 100%;
	background: #FAFAFA;
	overflow: auto;
	
	.padding {
		padding: 10px;
	}
}

Babel + JSX

const { h, Component, render } = preact;
const Markup = preactMarkup;
/**@jsx h*/


// Demo: textarea on the left, <Markup> on the right. Renders on change.
class App extends Component {
	componentDidMount() {
		this.loadExample();
	}

	// loads HTML example from a Gist
	loadExample() {
		fetch('https://gist.githubusercontent.com/developit/2c6aa8e40bd3ab251968/raw/c470e7e82fcc3eaeea1e3bc26d0829b7592ebb06/example.html')
			.then( r => r.text() )
			.then( markup => this.setState({ type:'html', markup }) );
	}
	
	// click on the error button to show the error
	showError = () => {
		alert(this.state.error);
	};
	
	// clear error on success (<Markup> fires no event for success)
	componentWillUpdate({ }, { markup, type }) {
		if (markup!==this.lastMarkup || type!==this.lastType) {
			this.state.error = null;
			this.lastMarkup = markup;
			this.lastType = type;
		}
	}

	render({ }, { markup, type, error }) {
		// components to use as custom elements:
		let components = {
			Sidebar,
			Toolbar,
			WidgetA,
			OtherWidget
		};

		return (
			<div id="app">
				<div class="editor">
					<div class="toolbar">
						<button onClick={::this.loadExample}>Load Example Gist</button>
						<select value={type} onChange={this.linkState('type')}>
							<option value="xml">XML (Strict)</option>
							<option value="html">HTML5</option>
						</select>
						{ error ? (
							<button onClick={::this.showError}>Error</button>
						) : null }
					</div>

					<textarea value={markup} onInput={this.linkState('markup')} />
				</div>

				<div class="preview">
					<Markup
						type={type}
						markup={markup}
						components={components}
						onError={this.linkState('error', 'error')} />
				</div>
			</div>
		);
	}
}



// creates a dummy component that just
// shows its name and some debug info:
const createPlaceholderComponent = name => ({ children, ...props }) => (
	<div class="placeholder-component" data-component={name} {...props}>
		<h4>{ name }</h4>
		<pre>{...