JSFiddle - React, Tailwind, and code Playground

by knrm720

HTML

<script src="https://cdn.jsdelivr.net/kefir/3.1.0/kefir.js"></script>
<div id="draggable">Drag me</div>

CSS

#draggable {
    width: 50px;
    height: 50px;
    position: absolute;
    background: #b9ffb9;
    cursor: move;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    padding: .2em;
}

JavaScript

// Pure functions

function eventsPositionDiff(prevEvent, nextEvent) {
  return {
    x: nextEvent.clientX - prevEvent.clientX,
    y: nextEvent.clientY - prevEvent.clientY
  };
}

function applyMove(currentPosition, move) {
  return {
    x: currentPosition.x + move.x,
    y: currentPosition.y + move.y
  };
}


// Primary sources

var mouseDowns = Kefir.fromEvents(document.querySelector('#draggable'), 'mousedown');
var mouseUps = Kefir.fromEvents(document, 'mouseup');
var mouseMoves = Kefir.fromEvents(document, 'mousemove');


// Compose primary sources to create observables we need

var moves = mouseDowns.flatMap(function(downEvent) {
  return mouseMoves.takeUntilBy(mouseUps)
    .diff(eventsPositionDiff, downEvent);
});

var position = moves.scan(applyMove, {x: 0, y: 0});


// Add side effect

var el = document.querySelector('#draggable');
position.onValue(function(pos) {
  el.style.top = pos.y + 'px';
  el.style.left = pos.x + 'px';
});