Skip to content

Instantly share code, notes, and snippets.

@bwaidelich
Forked from mpj/index.html
Last active March 23, 2023 14:44
Show Gist options
  • Save bwaidelich/aa5f33c4937e070dd3c53c6345623167 to your computer and use it in GitHub Desktop.
Save bwaidelich/aa5f33c4937e070dd3c53c6345623167 to your computer and use it in GitHub Desktop.
<!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/[email protected]/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