From 5341876a641c2a25cec459b5ef4ef1096ac0ea90 Mon Sep 17 00:00:00 2001 From: Eric Wertz Date: Wed, 4 Jun 2025 19:26:18 -0400 Subject: [PATCH] new toolbar button component --- frontend/components/ToolbarButton.tsx | 105 ++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 frontend/components/ToolbarButton.tsx diff --git a/frontend/components/ToolbarButton.tsx b/frontend/components/ToolbarButton.tsx new file mode 100644 index 0000000..6df8e0f --- /dev/null +++ b/frontend/components/ToolbarButton.tsx @@ -0,0 +1,105 @@ +import { Fragment, h, JSX } from 'preact'; +import { useState, useRef, useEffect } from 'preact/hooks'; + +export interface MenuOption { + label: string; + onClick: () => void; + disabled?: boolean; + icon?: JSX.Element; +} + +export interface ToolbarButtonProps { + icon: JSX.Element; + onClick?: () => void; + title: string; + disabled?: boolean; + active?: boolean; + separatorAfter?: boolean; + menuOptions?: MenuOption[]; +} + +export const ToolbarButton = ({ + icon, + onClick, + title, + disabled, + active, + separatorAfter, + menuOptions +}: ToolbarButtonProps) => { + const [showMenu, setShowMenu] = useState(false); + const buttonRef = useRef(null); + const menuRef = useRef(null); + + const hasMenu = menuOptions && menuOptions.length > 0; + + // Handle outside clicks to close menu + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + showMenu && + buttonRef.current && + menuRef.current && + !buttonRef.current.contains(event.target as Node) && + !menuRef.current.contains(event.target as Node) + ) { + setShowMenu(false); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [showMenu]); + + const handleButtonClick = () => { + if (disabled) return; + + if (hasMenu) { + setShowMenu(!showMenu); + } else if (onClick) { + onClick(); + } + }; + + const handleMenuItemClick = (menuItemOnClick: () => void) => { + menuItemOnClick(); + setShowMenu(false); + }; + + return ( +
+ + + {hasMenu && showMenu && ( +
+ {menuOptions.map((option, index) => ( + + ))} +
+ )} +
+ ); +}; + +export default ToolbarButton; \ No newline at end of file -- 2.49.0