import { usePortal } from '@agent/hooks/usePortal'; import { isChangeSiteDesignWorkflowAvailable } from '@agent/lib/util'; import animationWorkflow from '@agent/workflows/theme/change-animation'; import changeSiteDesignWorkflow from '@agent/workflows/theme/change-site-design'; import vibesWorkflow from '@agent/workflows/theme/change-site-vibes'; import fontsWorkflow from '@agent/workflows/theme/change-theme-fonts-variation'; import variationWorkflow from '@agent/workflows/theme/change-theme-variation'; import { createPortal, useEffect, useRef, useState } from '@wordpress/element'; import { __, isRTL } from '@wordpress/i18n'; import { Icon, moreVertical } from '@wordpress/icons'; import { AnimatePresence, motion } from 'framer-motion'; export const OptionsPopover = () => { const popoutNode = usePortal('extendify-agent-border-frame-mount'); const buttonRef = useRef(null); const firstButtonRef = useRef(null); const [topRight, setTopRight] = useState(null); const onOpen = () => { if (topRight) return setTopRight(null); const rect = buttonRef.current.getBoundingClientRect(); setTopRight({ top: rect.bottom + 4, right: window.innerWidth - rect.right, left: rect.left, }); }; const onClose = () => { setTopRight(null); buttonRef.current?.focus(); }; useEffect(() => { if (!topRight || !firstButtonRef.current) return; firstButtonRef.current.focus(); }, [topRight]); useEffect(() => { // click away const handle = (e) => { if (buttonRef.current.contains(e.target)) return; if (popoutNode?.contains(e.target)) return; setTopRight(null); }; window.addEventListener('click', handle); return () => window.removeEventListener('click', handle); }, [popoutNode]); if (!popoutNode) return null; return ( <> {createPortal( topRight ? ( ) : null, popoutNode, )} ); }; const buttons = [ { name: fontsWorkflow.example.text, available: fontsWorkflow.available, icon: fontsWorkflow.icon, }, { name: variationWorkflow.example.text, available: variationWorkflow.available, icon: variationWorkflow.icon, }, { name: vibesWorkflow.example.text, available: vibesWorkflow.available, icon: vibesWorkflow.icon, }, { name: animationWorkflow.example.text, available: animationWorkflow.available, icon: animationWorkflow.icon, }, ...(isChangeSiteDesignWorkflowAvailable() ? [ { name: changeSiteDesignWorkflow.example.text, available: changeSiteDesignWorkflow.available, onSelect: changeSiteDesignWorkflow.onSelect, icon: changeSiteDesignWorkflow.icon, }, ] : []), ]; const Popover = ({ position, onClose, firstItemRef }) => { useEffect(() => { const handle = (e) => { if (e.key === 'Escape') { e.preventDefault(); onClose(); } }; window.addEventListener('keydown', handle); return () => window.removeEventListener('keydown', handle); }, [onClose]); return ( { e.stopPropagation(); e.preventDefault(); if (e.key === 'Escape') return onClose(); const curr = document.activeElement; if (e.key === 'ArrowDown' || (e.key === 'Tab' && !e.shiftKey)) { if (curr.nextSibling) { return curr.nextSibling.focus(); } return firstItemRef.current.focus(); } if (e.key === 'ArrowUp' || (e.key === 'Tab' && e.shiftKey)) { if (curr.previousSibling) { return curr.previousSibling.focus(); } return curr.parentNode.lastChild.focus(); } if (e.key === 'Enter') { return curr.click(); } }} > {buttons .filter(({ available }) => available()) .map(({ name, icon }, i) => ( ))} ); };