JSFiddle - React, Tailwind, and code Playground

by rich_harris

HTML

<script src="http://cdn.ractivejs.org/edge/ractive.js"></script>
<div id='container'></div>

    <script id='main' type='text/ractive'>
        <box boxes="{{boxes}}" />
    </script>
    <script id='boxes' type='text/ractive'>
    <table>
        <thead>
            <tr><th>Width</th><th>Height</th><th>Area</th></tr>
        </thead>
        
        <tbody>
            {{#boxes}}
            <tr><td>{{width}}</td><td>{{height}}</td><td>{{area}}</td></tr>
            {{/boxes}}
        </tbody>
    </table>
    
    
    <table>
        <thead>
            <tr><th>Width</th><th>Height</th><th>Area</th></tr>
        </thead>
        
        <tbody>
            {{#boxes}}
            <tr><td><input type='number' value='{{width}}'></td><td><input type='number' value='{{height}}'></td><td>{{area}}</td></tr>
            {{/boxes}}
        </tbody>
    </table>
</script>

CSS

body {
    font-family: 'Helvetica Neue', 'Arial';
    font-size: 16px;
    color: #353535;
}

table {
    border-spacing: 0;
    margin: 0 0 2em 0;
}

th {
    background-color: #eee;
}

td, th {
    border-bottom: 1px solid #eee;
    padding: 0.2em 1em;
    width: 6em;
    text-align: right;
}

td {
    
}

input[type="number"] {
    font-size: inherit;
    font-family: inherit;
    width: 3.5em;
    text-align: right;
    padding: 0;
}

JavaScript

var littleBox, mediumBox, bigBox, ractive, Box, boxAdaptor;

Box = function ( width, height ) {
    this.width = width;
    this.height = height;
};

Box.prototype = {
    getArea: function () {
        return this.width * this.height;
    },
    setWidth: function ( width ) {
        this.width = width;
    },
    setHeight: function ( height ) {
        this.height = height;
    }
};

boxAdaptor = {
    // Ractive uses the `filter` function to determine whether something
    // needs to be wrapped or not. For example 'boxes' doesn't need to be
    // wrapped because it's an array, but 'boxes.0' - which is the same as
    // our `littleBox` variable - does.
    filter: function ( object ) {
        return object instanceof Box;
    },
    
    // If an object passes the filter, we wrap it.
    wrap: function ( ractive, box, keypath, prefixer ) {
        // We can simply overwrite the prototype methods with ones that
        // do the same thing, but also notify Ractive about the changes
        box.setWidth = function ( width ) {
            
            this.width = width;
            
            // Very often, inside adaptors, we need to turn _relative keypaths_
            // into _absolute keypaths_. For example if this box's keypath is
            // 'boxes.0', we need to turn 'width' and 'area' into 'boxes.0.width'
            // and 'boxes.0.area'.
            //
            // This is such a common requirement that a helper function - 
            // `prefixer` - is automatically generated for each wrapper.
            ractive.set( prefixer({
                width: width,
                area: box.getArea()
            }));
        };
        
        box.setHeight = function ( height ) {
            this.height = height;
            
            ractive.set( prefixer({
                height: height,
                area: box.getArea()
            }));
        };
        
        // The wrapper we return is used by Ractive to interact with each box.
  ...