JSFiddle - React, Tailwind, and code Playground

by Kye Hohenberger

HTML

<script src="https://unpkg.com/preact/dist/preact.min.js"></script>
<script src="https://unpkg.com/proptypes"></script>
<script src="https://unpkg.com/preact-compat/dist/preact-compat.min.js"></script>
<script src="https://cdn.rawgit.com/developit/0c2755a85948cb62e663170e403c9697/raw/9591812d5742f25e2df6b90133ccc70ba2241485/preact-polyfill.js"></script>
<script src="https://unpkg.com/[email protected]/umd/data-driven-motion.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/preact-scroll-viewport.min.js"></script>
<script src="https://cdn.pubnub.com/sdk/javascript/pubnub.4.4.4.min.js"></script>

CSS

html, body {
	background: #EEE;
	margin: 0;
	font: 16px/1.3 'Helvetica Neue', helvetica, arial, sans-serif;
	color: #000;
  width: 100%;
  height: 100%;
}

.count {
	position: fixed;
	right: 0;
	top: 0;
	padding: 10px;
	background: #000;
	color: #FFF;
	z-index: 100;
}

.item {
	position: relative;
	box-sizing: border-box;
	padding: 10px;
	width: 100%;
	height: 90px;
	background: #FFF;
	border-bottom: 1px solid #DDD;
	overflow: hidden;
	contain: strict;
}

.avatar {
	float: left;
	margin: 0 10px 0 0;
	width: 48px;
	height: 48px;
	img {
		width: 48px;
		height: 48px;
		border-radius: 3px;
	}
}

.author-name {
	color: #555;
	text-decoration: none;
	font-weight: bold;
}

.author-screenname {
	color: #AAA;
	margin-left: 1em;
	text-decoration: none;
	font-size: 80%;
}

.text {
	margin: 0;
	padding: 0;
	overflow: hidden;
}

Babel + JSX

const { h, Component, render } = preact
/** @jsx h */
const { Motion } = DDM // https://github.com/tkh44/data-driven-motion

const WOBBLY_SPRING = { stiffness: 280, damping: 30 }

/**  Demo: Stream twitter firehose into
 *  a naive VDOM list with shouldComponentUpdate.
 */

class Demo extends Component {
  state = {
    messages: []
  }

  handleMessage = msg => {
    // we'll mutate in-place to save some copy ops
    // TIP: you can store VDOM in state!
    // Avoids constantly re-mapping data -> VDOM in render.
    // this.state.messages.push(
    //   <Message id={msg.message.id_str} message={msg.message} />
    // );
    this.state.messages.push(msg)
    // just trigger a state update
    this.setState()
  }

  componentDidMount () {
    let stream = new PubNub({
      subscribeKey: 'sub-c-78806dd4-42a6-11e4-aed8-02ee2ddab7fe'
    })
    stream.addListener({
      message: this.handleMessage
    })
    stream.subscribe({
      channels: ['pubnub-twitter']
    })
  }

  render ({}, { messages }) {
    return (
      <div class="list" style={{ width: '100%', height: '100%' }}>
        <span class="count">{messages.length} tweets ({messages.length * 9} elements)</span>
        <Motion
          data={this.state.messages}
          component={(<div overscan={20} style={{ width: '100%', height: '100%' }} />)}
          getKey={(msg, i) => i + msg.message.id_str}
          onComponentMount={() => ({ y: 0 })}
          onRender={(data, i, spring) => {
            return ({
              y: spring(i * 90, WOBBLY_SPRING)
            })
          }}
          onRemount={(data, i) => ({ y: 200 })}
          onUnmount={(data, spring) => ({ y: spring(90) })}
          render={(key, msg, style, dataIndex) => {
            return (
              <Message
                key={key}
                id={msg.message.id_str}
                message={msg.message}
                style={{
                	position: 'absolute',
                  top: 0,
                  left: 0,
  ...