Skip to content

Instantly share code, notes, and snippets.

@threepointone
Last active September 24, 2016 18:50
Show Gist options
  • Save threepointone/5d02c7cdef4c017f63cb to your computer and use it in GitHub Desktop.
Save threepointone/5d02c7cdef4c017f63cb to your computer and use it in GitHub Desktop.
import React, {Component} from 'react';
import {render} from 'react-dom';
import {take, put, fork, join, cps, call, cancel, race, runSaga, SagaCancellationException} from 'redux-saga';
const styles = {
app: {
position: 'absolute',
width: 200,
height: 200,
backgroundColor: 'red',
display: 'block',
color: 'white',
transformOrigin: 'center center',
transform: 'translateX(-50%) translateY(-50%)'
}
}
// Event iterator
function events(target, event) {
let fns = [], handler = e => {
fns.forEach(fn => fn(null, e));
fns = [];
};
target.addEventListener(event, handler);
return {
next(fn) {
fns.push(fn);
},
dispose(){
target.removeEventListener(event, handler);
fns = handler = null;
}
}
}
// fake redux for experimenting
const store = {
state : {pageX: 200, pageY: 200},
listeners: [],
reduce(state, action = {}){
switch(action.type){
case 'setState':
return {...state, ...action.payload};
default:
return state;
}
},
dispatch(action){
store.listeners.forEach(x => x(action));
store.state = store.reduce(store.state, action);
render(<App/>, document.getElementById('app'));
},
subscribe(callback){
store.listeners.push(callback);
return () => store.listeners = store.listeners.filter(x => x !== callback);
}
}
function setState(state){
return put({type: 'setState', payload: state});
}
// drag and drop in one function
function * run(){
while(true){
// wait until mousedown event
let e = yield take('mousedown');
e.payload.preventDefault();
e.payload.stopPropagation();
// start listening to mousemove and mouseup events
let up$ = events(window, 'mouseup');
let move$ = events(window, 'mousemove');
while(true){
let {move} = yield race({
up: cps(up$.next),
move: cps(move$.next)
});
if(move){
move.preventDefault();
move.stopPropagation();
let {pageX, pageY} = move;
yield setState({pageX, pageY});
}
else break;
}
// cleanup
up$.dispose();
move$.dispose();
}
}
class App extends Component{
render(){
let {pageX, pageY} = store.state;
return <div
style={{...styles.app, top: pageY, left: pageX}}
onMouseDown={e => store.dispatch({type: 'mousedown', payload: e})} />;
}
}
// startup
runSaga(run(), store);
store.dispatch({type: 'bootup'});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment