Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save johnwheeler/5f6f6eb53e92782ff3d0b0f480a3b11a to your computer and use it in GitHub Desktop.
Save johnwheeler/5f6f6eb53e92782ff3d0b0f480a3b11a to your computer and use it in GitHub Desktop.
import { Button, Flex } from '@chakra-ui/react'
import { createMachine, guard, invoke, reduce, state, transition } from 'robot3'
import { useEffect, useState } from 'react'
import { createUseMachine } from 'robot-hooks'
const useMachine = createUseMachine(useEffect, useState)
// @formatter:off
const mergeIncoming = reduce((c, e) => ({ ...c, ...e.value }))
const ifNoInteraction = guard(c => !c.interact)
const animationMachineDef = {
pan: state(
transition('pan', 'pan', mergeIncoming),
transition('zoom', 'zoom', mergeIncoming),
transition('done', 'done', ifNoInteraction)
),
zoom: state(
transition('zoom', 'zoom', mergeIncoming),
transition('pan', 'pan', mergeIncoming),
transition('done', 'done', ifNoInteraction)
),
done: state()
}
const guiMachine = createMachine({
idle: state(
transition('animate', 'animate'),
transition('select', 'select'),
),
select: state(
transition('animate', 'animate'),
transition('select', 'idle'),
),
animate: invoke(
(c, e) => {
return e.value === 'zoom' ?
createMachine('zoom', animationMachineDef) :
createMachine(animationMachineDef)
},
transition('done', 'idle'),
transition('animate', 'idle'),
transition('select', 'select'),
),
})
// @formatter:on
const Page = () => {
const [, , service] = useMachine(guiMachine)
useEffect(() => {
const onkeydown = (e) => {
if (e.key === 'Meta') {
service.send({ type: 'animate' })
}
}
const onkeyup = (e) => {
if (e.key === 'Meta') {
service.child?.send({ type: 'done' })
}
}
const onwheel = (e) => {
if (!e.metaKey) return
service.send({ type: 'animate', value: 'zoom' })
}
document.addEventListener('keydown', onkeydown)
document.addEventListener('keyup', onkeyup)
document.addEventListener('wheel', onwheel)
return () => {
document.removeEventListener('keydown', onkeydown)
document.removeEventListener('keyup', onkeyup)
document.removeEventListener('wheel', onwheel)
}
}, [])
return (
<Flex gap={3}
p={5}>
<Button
isActive={service.machine.current === 'select'}
onClick={() => {
service.send({ type: 'select' })
}}
>
Select
</Button>
<Button
isActive={service.machine.current === 'animate'}
onClick={() => {
service.send({ type: 'animate' })
}}
>
Animate
</Button>
{service.machine.current === 'animate' && (
<>
<Button
isActive={service.child.machine.current === 'pan'}
onClick={() => service.child.send({ type: 'pan', value: { interact: true } })}>
Pan
</Button>
<Button
isActive={service.child.machine.current === 'zoom'}
onClick={() => service.child.send({ type: 'zoom', value: { interact: true } })}>Zoom</Button>
</>
)}
</Flex>
)
}
export default Page
@johnwheeler
Copy link
Author

You will need these packages

@chakra-ui/react
robot3
robot-hooks

@ChuaJingYong
Copy link

Thanks for taking the time and effort to do this awesome demo! Love it and thanks a bunch again

@johnwheeler
Copy link
Author

For sure ChuaJingYong!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment