refactor: rewrite menu with floating ui

This commit is contained in:
MAZE 2024-01-02 16:54:29 +03:30
parent 17027e299b
commit 8beb42cb1b
2 changed files with 51 additions and 14 deletions

View File

@ -24,9 +24,6 @@
} }
& .menu { & .menu {
position: absolute;
right: 0;
bottom: calc(100% + 12px);
width: 200px; width: 200px;
padding: 4px; padding: 4px;
background-color: var(--color-neutral-100); background-color: var(--color-neutral-100);

View File

@ -1,6 +1,18 @@
import { useState } from 'react'; import { useState } from 'react';
import { IoMenu, IoClose } from 'react-icons/io5/index'; import { IoMenu, IoClose } from 'react-icons/io5/index';
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
import {
useFloating,
autoUpdate,
offset,
flip,
shift,
useClick,
useDismiss,
useRole,
useInteractions,
FloatingFocusManager,
} from '@floating-ui/react';
import { useSoundStore } from '@/store'; import { useSoundStore } from '@/store';
import { slideY, fade, mix } from '@/lib/motion'; import { slideY, fade, mix } from '@/lib/motion';
@ -14,18 +26,44 @@ export function Menu() {
const variants = mix(slideY(-20), fade()); const variants = mix(slideY(-20), fade());
const { context, floatingStyles, refs } = useFloating({
middleware: [offset(12), flip(), shift()],
onOpenChange: setIsOpen,
open: isOpen,
placement: 'top-end',
whileElementsMounted: autoUpdate,
});
const click = useClick(context);
const dismiss = useDismiss(context);
const role = useRole(context);
const { getFloatingProps, getReferenceProps } = useInteractions([
click,
dismiss,
role,
]);
return ( return (
<div className={styles.wrapper}> <div className={styles.wrapper}>
<button <button
aria-label="Menu" aria-label="Menu"
className={styles.menuButton} className={styles.menuButton}
ref={refs.setReference}
onClick={() => setIsOpen(prev => !prev)} onClick={() => setIsOpen(prev => !prev)}
{...getReferenceProps()}
> >
{isOpen ? <IoClose /> : <IoMenu />} {isOpen ? <IoClose /> : <IoMenu />}
</button> </button>
<AnimatePresence> <AnimatePresence>
{isOpen && ( {isOpen && (
<FloatingFocusManager context={context} modal={false}>
<div
ref={refs.setFloating}
style={floatingStyles}
{...getFloatingProps()}
>
<motion.div <motion.div
animate="show" animate="show"
className={styles.menu} className={styles.menu}
@ -37,6 +75,8 @@ export function Menu() {
Shuffle Sounds Shuffle Sounds
</button> </button>
</motion.div> </motion.div>
</div>
</FloatingFocusManager>
)} )}
</AnimatePresence> </AnimatePresence>
</div> </div>