From 9eb1625ec5de3c221ed0445dde874fcb1dc3ff48 Mon Sep 17 00:00:00 2001
From: Sam Nystrom <sam@samnystrom.dev>
Date: Wed, 13 Mar 2024 18:01:48 +0000
Subject: feat: add menu components

---
 src/components/ButtonMenu.tsx | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)
 create mode 100644 src/components/ButtonMenu.tsx

(limited to 'src/components/ButtonMenu.tsx')

diff --git a/src/components/ButtonMenu.tsx b/src/components/ButtonMenu.tsx
new file mode 100644
index 0000000..6a2b73e
--- /dev/null
+++ b/src/components/ButtonMenu.tsx
@@ -0,0 +1,42 @@
+import type { ComponentChildren } from 'preact';
+import { useEffect, useRef, useId } from 'preact/hooks';
+import { useSignal, batch } from '@preact/signals';
+import Button from './Button.tsx';
+import Menu from './Menu.tsx';
+import './ButtonMenu.css';
+
+export interface ButtonMenuProps {
+	children: ComponentChildren;
+	label: string;
+}
+
+const ButtonMenu = ({ children, label }: ButtonMenuProps) => {
+	const id = useId();
+	const ref = useRef(null);
+	const x = useSignal(0);
+	const y = useSignal(0);
+
+	const updateRect = () => batch(() => {
+		const rect = ref.current?.getBoundingClientRect();
+		if (!rect) return;
+		x.value = rect.x;
+		y.value = rect.y + rect.height + 1;
+	});
+	useEffect(updateRect, [ref.current]);
+
+	return (
+		<div
+			class="__ButtonMenu"
+			ref={ref}
+			onScroll={updateRect}
+			style={`--anchor-x: ${x}px; --anchor-y: ${y}px;`}
+		>
+			<Button kind="ghost" popoverTarget={id}>{label}</Button>
+			<Menu id={id} popover="auto">
+				{children}
+			</Menu>
+		</div>
+	);
+};
+
+export default ButtonMenu;
-- 
cgit v1.2.3

