<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
<title>Intro to XState</title> | |
<link rel="stylesheet" href="styles.css" /> | |
</head> | |
<body> | |
<div id="box"></div> | |
<script src="https://unpkg.com/xstate@4.8.0/dist/xstate.js"></script> | |
<script src="index.js"></script> | |
</body> | |
</html> |
const { createMachine, interpret, assign } = XState; | |
const dragDropMachine = createMachine({ | |
initial: 'idle', | |
context: { | |
// the position of the box | |
x: 0, | |
y: 0, | |
// where you clicked relative to the target element | |
dx: 0, | |
dy: 0, | |
}, | |
states: { | |
idle: { | |
on: { | |
// event: nextstate | |
mousedown: { | |
target: 'dragging', | |
actions: assign((context, mouseEvent) => { | |
const boundingRect = mouseEvent.target.getBoundingClientRect() | |
return { | |
...context, | |
x: boundingRect.x, | |
y: boundingRect.y, | |
dx: mouseEvent.clientX - boundingRect.x, | |
dy: mouseEvent.clientY - boundingRect.y | |
} | |
}) | |
} | |
} | |
}, | |
dragging: { | |
on: { | |
mousemove: { | |
target: 'dragging', | |
actions: assign((context, mouseEvent) => { | |
return { | |
...context, | |
x: mouseEvent.clientX - context.dx, | |
y: mouseEvent.clientY - context.dy | |
} | |
}) | |
}, | |
mouseup: { | |
target: 'idle', | |
} | |
} | |
} | |
} | |
}) | |
const body = document.body; | |
const box = document.getElementById('box') | |
const dragDropService = interpret(dragDropMachine) | |
.onTransition(state => { | |
if (state.changed) { | |
console.log(state.context) | |
box.style.setProperty('left', state.context.x + 'px') | |
box.style.setProperty('top', state.context.y + 'px') | |
body.dataset.state = state.toStrings().join(' ') | |
} | |
}) | |
.start(); | |
box.addEventListener('mousedown', event => { | |
dragDropService.send(event) | |
}) | |
body.addEventListener('mouseup', event => { | |
dragDropService.send(event) | |
}) | |
body.addEventListener('mousemove', event => { | |
dragDropService.send(event) | |
}) |
* { | |
position: relative; | |
box-sizing: border-box; | |
} | |
body, | |
html { | |
height: 100%; | |
width: 100%; | |
margin: 0; | |
padding: 0; | |
} | |
body::before { | |
content: attr(data-state); | |
font-size: 2rem; | |
font-family: monospace; | |
position: absolute; | |
padding: 1rem; | |
z-index: 99; | |
right: 0; | |
} | |
body[data-state="dragging"] #box { | |
background: red; | |
} | |
#box { | |
height: 20vmin; | |
width: 20vmin; | |
background: #99ccff; | |
border-radius: 1rem; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment