JSFiddle - React, Tailwind, and code Playground

by ozzon91

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.6/rx.all.js"></script>
<script src="https://cdn.jsdelivr.net/ramda/0.18.0/ramda.min.js"></script>
<div class="container">
    <div class="item item-1">1</div>
    <div class="item item-2">2</div>
    <div class="item item-3">3</div>
    <div class="item item-4">4</div>
    <div class="item item-5">5</div>
    <div class="item item-6">6</div>
</div>

CSS

.container {
    display: flex;
    justify-content: space-between;
    width: 700px;
}
.item {
    font-size: 40px;
    width: 100px;
    height: 100px;
    outline: 1px solid #ccc;
    text-align: center;
    line-height: 100px;
    cursor: pointer;
    transition: background-color 0.5s ease;
    background-color: yellow;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
.item:hover {
    background-color: lightblue;
}
.item.active {
    outline: 2px solid red;
}

Babel + JSX

const {
    fromEvent
} = Rx.Observable;
const {
    unapply, identity, equals, apply, lt, or, not, map, pipe, pluck, prop, invoker, curry
} = R;

const fromKey = curry((type, code) => fromEvent(document.body, type).filter(pipe(prop('keyCode'), equals(code))));

const orObs = (o1, o2) => o1.combineLatest(o2, or);
const notObs = o => o.map(not);

const fromKeyDown = fromKey('keydown');
const fromKeyUp = fromKey('keyup');

const fromKeyPress = code => fromKeyDown(code).map(true).merge(fromKeyUp(code).map(false)).shareValue(false);

const [ctrlKey, shiftKey] = R.map(fromKeyPress)([17, 16]);

const clickItem = fromEvent($('.item'), 'click');

clickItem.pausable(notObs(orObs(ctrlKey, shiftKey)))
	.map(pipe(prop('target'), identity($)))
    .subscribe(el => el.toggleClass('active').siblings().removeClass('active'));

clickItem.pausable(ctrlKey).map(pipe(prop('target'), identity($))).subscribe(el => el.toggleClass('active'));

clickItem.pausable(notObs(shiftKey)).combineLatest(
        clickItem.pausable(shiftKey),
        unapply(identity)
    )
    .filter(pipe(pluck('timeStamp'), apply(lt)))
    .map(pipe(pluck('currentTarget'), map(pipe(identity($), invoker(0, 'index')))))
    .subscribe(([ai, bi]) => $(".item").slice.apply($(".item"), ai < bi ? [ai, bi + 1] : [bi, ai + 1]).addClass('active'));