JSFiddle - React, Tailwind, and code Playground

by Luke May

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.3.4/js/tether.js"></script>
<div class="container root gen0" data-bind="
    click: root().onClick,
    clickBubble: false
">
    <div class="container alice gen1" data-bind="
        click: root().children()[0].onClick,
        clickBubble: false
    ">
        <div class="container amy gen2" data-bind="
            click: root().children()[0].children()[0].onClick,
            clickBubble: false
        ">
        </div>
        <div class="container artemis gen2" data-bind="
            click: root().children()[0].children()[1].onClick,
            clickBubble: false
        ">
        </div>
    </div>
    <div class="container briana gen1" data-bind="
        click: root().children()[1].onClick,
        clickBubble: false
    ">
        <div class="container bridget gen2" data-bind="
            click: root().children()[1].children()[0].onClick,
            clickBubble: false
        ">
        </div>
        <div class="container betsy gen2" data-bind="
            click: root().children()[1].children()[1].onClick,
            clickBubble: false
        ">
        </div>
    </div>
</div>

CSS

body {
    position: absolute;
    width: calc(100% - 100px);
    height: calc(100% - 100px);
    padding: 50px;
    margin: 0;
    background-color: #eeeeee;
}

.container {
    display: inline-block;
    padding: 10px;
    margin: 10px;
    border-width: 1px;
    border-style: solid;
    position: relative;
    overflow: auto;
}
.gen0 {
    border-color: #c52;
}
.gen1 {
    border-color: #25c;
}
.gen2 {
    border-color: #2c5;
}

.root {
    width: 800px;
    height: 600px;
}
.alice {
    display: inline-block;
    width: 300px;
    height: 500px;
}
.amy {
    display: inline-block;
    width: 100px;
    height: 1200px;
}
.artemis {
    display: inline-block;
    width: 100px;
    height: 400px;
}
.briana {
    display: inline-block;
    width: 300px;
    height: 500px;
}
.bridget {
    width: 600px;
    height: 600px;
}
.betsy {
    width: 200px;
    height: 200px;
}


.sc-corner {
    width: 10px;
    height: 10px;
    border: solid 1px red;
}
.sc-corner.tether-out-of-bounds {
    display: none;
}

JavaScript

var cornerPieces = {};
var tethers = {};
var selectedComponents = {};

var createCornerPieces = function (id) {
    var target = selectedComponents[id];
    var $target = $(target);;
    if (!cornerPieces[id]) {
        cornerPieces[id] = {};
        cornerPieces[id].tl = $('<div class="sc-corner corner-top-left"></div>');
        cornerPieces[id].tr = $('<div class="sc-corner corner-top-right"></div>');
        cornerPieces[id].bl = $('<div class="sc-corner corner-bottom-left"></div>');
        cornerPieces[id].br = $('<div class="sc-corner corner-bottom-right"></div>');
        var $parent = $target.parent();
        $parent.append(cornerPieces[id].tl);
        $parent.append(cornerPieces[id].tr);
        $parent.append(cornerPieces[id].bl);
        $parent.append(cornerPieces[id].br);
    }
};

var destroyCornerPieces = function (id) {
    _.each(cornerPieces[id], function (val) {
        if (val && val.remove) {
            val.remove();
        }
    });
    delete cornerPieces[id];
};

var createTethers = function (id) {
    tethers[id] = {};
    tethers[id].tl = new Tether({
        element: cornerPieces[id].tl[0],
        target: selectedComponents[id][0],
        attachment: 'top left',
        targetAttachment: 'top left',
        constraints: [
            {
                to: 'scrollParent'
            }
        ]
    });

    tethers[id].tr = new Tether({
        element: cornerPieces[id].tr[0],
        target: selectedComponents[id][0],
        attachment: 'top right',
        targetAttachment: 'top right',
        constraints: [
            {
                to: 'scrollParent'
            }
        ]
    });

    tethers[id].bl = new Tether({
        element: cornerPieces[id].bl[0],
        target: selectedComponents[id][0],
        attachment: 'bottom left',
        targetAttachment: 'bottom left',
        constraints: [
            {
                to: 'scrollParent'
            }
        ]
    });

    tethers[id].br = new Tether({
       ...