import React, { useEffect, useRef } from 'react'; import { DeviceMode } from '../../types'; export interface TopBarOverflowMenuProps { open: boolean; onClose: () => void; device: DeviceMode; onDeviceChange: (device: DeviceMode) => void; showGuides: boolean; onToggleGuides: () => void; onOpenTemplates: () => void; onOpenHeadCode: () => void; onPreview: () => void; /** Rendered `` -- passed in rather than * re-implemented here so the mobile menu reuses the exact same * lock/cap-aware button the desktop topbar shows. */ sitesmithNode: React.ReactNode; } /** * Mobile topbar "⋯" overflow menu (Phase A). At ≤768px, TopBar collapses to * just the back arrow, Undo/Redo, Save/Publish, and this menu -- everything * else that's inline on desktop (Templates, Sitesmith, Preview, Head Code, * the guides toggle, and the device-width switcher) moves in here so the * collapsed bar never overlaps or pushes controls off-screen. */ export const TopBarOverflowMenu: React.FC = ({ open, onClose, device, onDeviceChange, showGuides, onToggleGuides, onOpenTemplates, onOpenHeadCode, onPreview, sitesmithNode, }) => { const menuRef = useRef(null); useEffect(() => { if (!open) return; const handleClick = (e: MouseEvent) => { if (menuRef.current && !menuRef.current.contains(e.target as Node)) onClose(); }; const handleEsc = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); }; document.addEventListener('mousedown', handleClick); document.addEventListener('keydown', handleEsc); return () => { document.removeEventListener('mousedown', handleClick); document.removeEventListener('keydown', handleEsc); }; }, [open, onClose]); if (!open) return null; const runAndClose = (fn: () => void) => () => { fn(); onClose(); }; return ( Preview width {(['desktop', 'tablet', 'mobile'] as DeviceMode[]).map((d) => ( onDeviceChange(d)} title={d.charAt(0).toUpperCase() + d.slice(1)} aria-label={d.charAt(0).toUpperCase() + d.slice(1)} aria-pressed={device === d} > ))} Templates Preview Head Code {' '}{showGuides ? 'Hide Guides' : 'Show Guides'} {sitesmithNode} ); };