qwerty

by evgkch

HTML

<div id="app"></div>

CSS

body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  padding: 5px;
  display: flex;
  width: 100%;
}

td {
  padding: 3px;
  border: solid 1px black;
}

#field {
  width: 100%;
  height: 200px;
  border: solid 1px blue;
}

React

// mousedown, mouseup, mousemove, mousedrag, mousedrop
const MOUSEDOWN = 'mousedown';
const MOUSEUP = 'mouseup';
const MOUSEMOVE = 'mousemove';
const MOUSEDRAG = 'mousedrag';
const MOUSEDROP= 'mousedrop';

const transitions = {
	[MOUSEMOVE]: [
  	{
    	to: MOUSEMOVE,
      when: action => [action.type == 'onmousemove']
    },
    {
    	to: MOUSEDOWN,
      when: action => [action.type == 'onmousedown']
    },
  ],
	[MOUSEDOWN]: [
  	{
    	to: MOUSEUP,
      when: action => [action.type == 'onmouseup']
    },
    {
    	to: MOUSEDRAG,
      when: action => [action.type == 'onmousemove']
    },
  ],
  [MOUSEUP]: [
  	{
    	to: MOUSEMOVE,
      when: action => [action.type == 'onmousemove']
    },
    {
    	to: MOUSEDOWN,
      when: action => [action.type == 'onmousedown']
    },
   ],
   [MOUSEDRAG]: [
   	{
    	to: MOUSEDRAG,
      when: action => [action.type == 'onmousemove']
    },
    {
    	to: MOUSEDROP,
      when: action => [action.type == 'onmouseup']
    },
   ],
   [MOUSEDROP]: [
     {
       to: MOUSEMOVE,
       when: action => [action.type == 'onmousemove']
     },
     {
       to: MOUSEDOWN,
       when: action => [action.type == 'onmousedown']
     },
   ],
};

const onMouseMove = (x, y)=>({
	type: 'onmousemove',
  payload: { x, y }
});

const onMouseDown = ()=>({ type: 'onmousedown' });
const onMouseUp = ()=>({ type: 'onmouseup' });

const reducer = (cache, action)=>{
	switch(action.type)
  {
 	case 'onmousemove':
  	return Object.assign(cache, action.payload);
  default:
  	return false;
  }
}

const createFSM = (initialState, transitions, reducer)=>{
	let state = initialState;
  let cache = {};
	const perform = action => {
  	const transition = transitions[state].find(({ when })=>when(action, cache).every(condition => condition));
   	if (transition)
    {
    	const nextCache = reducer(cache, action);
      if (nextCache)
      	cache = nextCache;
      console.log(`${action.type}: ${state} -> ${transition.to}`);
      state =...