Created
May 29, 2024 04:10
-
-
Save johnwheeler/5f6f6eb53e92782ff3d0b0f480a3b11a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Thanks for taking the time and effort to do this awesome demo! Love it and thanks a bunch again
For sure ChuaJingYong!!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You will need these packages
@chakra-ui/react
robot3
robot-hooks